<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5799246</id><updated>2012-05-13T07:57:29.234Z</updated><category term='mathematics'/><category term='reiser4'/><category term='file system'/><category term='kernel'/><category term='programming'/><title type='text'>a very occasional diary</title><subtitle type='html'>nondescript</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.cofault.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default'/><link rel='alternate' type='text/html' href='http://www.cofault.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default?start-index=26&amp;max-results=25'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>64</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5799246.post-4574964662228882880</id><published>2012-05-11T20:20:00.000Z</published><updated>2012-05-11T20:53:09.193Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>A macro.</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div style="text-align: justify;"&gt;
&lt;a href="http://en.wikipedia.org/wiki/C_language"&gt;C language&lt;/a&gt; is wonderfully profound. After almost 20 years, I still find new ways to (ab-)use it. Here is a little problem:&lt;br /&gt;
&lt;blockquote&gt;
Define a macro &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;IN(x, set)&lt;/span&gt;, called as&lt;br /&gt;
&lt;blockquote class="tr_bq"&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;IN(x, (v0, v1, ..., vn))&lt;/span&gt;&lt;/blockquote&gt;
that expands into an expression&lt;br /&gt;
&lt;blockquote class="tr_bq"&gt;
&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;((x) == (v0) || (x) == (v1) || ... (x) == (vn))&lt;/span&gt;&amp;nbsp;&lt;/blockquote&gt;
which evaluates to true &lt;a href="http://en.wikipedia.org/wiki/Iff"&gt;iff&lt;/a&gt; &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;x&lt;/span&gt; is a member of set {&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;v0&lt;/span&gt;, ..., &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;vn&lt;/span&gt;}, where the type of &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;x&lt;/span&gt; and all &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;v&lt;/span&gt;s is the same. Alternatively, define a macro &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;IN1(x, ...)&lt;/span&gt; that expands to the same expression as &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;IN(x, (...))&lt;/span&gt;.&lt;/blockquote&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4574964662228882880?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4574964662228882880/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4574964662228882880' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4574964662228882880'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4574964662228882880'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2012/05/c-language-is-wonderfully-profound.html' title='A macro.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-8132210692954190981</id><published>2012-05-11T20:06:00.001Z</published><updated>2012-05-11T20:07:41.323Z</updated><title type='text'>You won't see this post (or maybe you will).</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-Dmic_PYhS-o/T61w2q4bqLI/AAAAAAAAOHY/-f_Vtg05LAg/s1600/cofault.png" imageanchor="1" style="margin-left:1em; margin-right:1em"&gt;&lt;img border="0" height="266" width="320" src="http://1.bp.blogspot.com/-Dmic_PYhS-o/T61w2q4bqLI/AAAAAAAAOHY/-f_Vtg05LAg/s320/cofault.png" /&gt;&lt;/a&gt;&lt;/div&gt;My ISP is blocking my blog. Am I an unwitting beacon of revolution?&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-8132210692954190981?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/8132210692954190981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=8132210692954190981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/8132210692954190981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/8132210692954190981'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2012/05/you-wont-see-this-post-or-maybe-you.html' title='You won&apos;t see this post (or maybe you will).'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/-Dmic_PYhS-o/T61w2q4bqLI/AAAAAAAAOHY/-f_Vtg05LAg/s72-c/cofault.png' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-8903228004689502384</id><published>2012-03-03T14:09:00.000Z</published><updated>2012-05-11T20:53:32.358Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>Riemann hypothesis, DIY</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
Continuing with &lt;a href="http://www.cofault.com/2009/08/trivial-exercise.html"&gt;useless exercises&lt;/a&gt;, let's look at &lt;a href="http://en.wikipedia.org/wiki/Prime_number"&gt;prime numbers&lt;/a&gt;. We shall use &lt;a href="http://en.wikipedia.org/wiki/Haskell_(programming_language)"&gt;Haskell&lt;/a&gt; this time.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;-- prime numbers: [2,3,5,7,11,13,17,19, ...]
pr :: [Int]
pr = [p | p &amp;lt;- [2 .. ], maximum [d | d &amp;lt;- [1 .. p - 1], p `mod` d == 0] == 1]
&lt;/pre&gt;
&lt;br /&gt;
The first line, starting with '--' is a comment. The second line declares 'pr' to have type "list of Int". Typings are optional in Haskell. The last line, uses "&lt;a href="http://en.wikipedia.org/wiki/List_comprehension"&gt;list comprehension&lt;/a&gt;" (yes, it is related to "&lt;a href="http://en.wikipedia.org/wiki/Set-builder_notation"&gt;set comprehension&lt;/a&gt;" used in &lt;a href="http://www.cofault.com/2011/11/unintentionally-yours.html"&gt;one of the recent posts&lt;/a&gt;) to define 'pr' as those elements of the infinite list [2, 3, 4, 5, ...] (denoted [2 ...]), whose maximal proper divisor is 1. This is a very inefficient, quadratic way to build the list of all primes.&lt;br /&gt;
&lt;br /&gt;
In addition, define a list of all &lt;a href="http://en.wikipedia.org/wiki/Twin_prime"&gt;twin primes&lt;/a&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;-- twin primes, primes whose difference is 2
twinp :: [Int]
twinp = [n | n &amp;lt;- pr, (n + 2) `elem` (take (n + 4) pr)]
&lt;/pre&gt;
&lt;br /&gt;
"x `elem` s" is true &lt;a href="http://en.wikipedia.org/wiki/Iff"&gt;iff&lt;/a&gt; x is en element of list s. Ugly '(n + 2) `elem` (take (n + 4) pr)' is needed because for an infinite s, "x `elem` s" either returns True or never returns: without some additional knowledge about the list, the only way to determine whether x belongs to it is by linear search, which might never terminate. In our case, 'pr' is strictly ascending and hence the search can be limited to some finite prefix of the list ((take n s) returns first n elements of s). Perhaps there is a way to specify list properties that `elem` can rely on, I don't know, I opened &lt;a href="http://www.haskell.org/onlinereport/haskell2010/haskell.html#haskellpa1.html"&gt;the Haskell specification&lt;/a&gt; an only hour ago.&lt;br /&gt;
&lt;br /&gt;
Let's do some "visualisation":&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;-- an (infinite) string containing a '+' for each element of s and '.' for each
-- element not in s, assuming that s is ascending and s !! n &amp;gt; n.
-- dot pr == "..++.+.+...+.+.. ..."
dot :: [Int] -&amp;gt; [Char]
dot s = [ if (x `elem` (take (x + 2) s)) then '+' else '.' | x &amp;lt;- [0 ..]]
&lt;/pre&gt;
&lt;br /&gt;
For example, (dot pr) is an infinite string containing "+" for each prime number and "." for each composite.&lt;br /&gt;
&lt;br /&gt;
By printing (dot s) in rows, k columns each, some hopefully interesting information about distribution of elements of s can be obtained. First, split s into sub-lists of length k:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;-- (dot s), sliced into sub-strings of length k, separated by newlines
sl :: [Int] -&amp;gt; Int -&amp;gt; [[Char]]
sl s k = ['\n' : [ (dot s) !! i | i &amp;lt;- [j*k .. (j+1)*k - 1]] | j &amp;lt;- [0 ..]]
&lt;/pre&gt;
&lt;br /&gt;
then, concatenate them all:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;-- concatenation of slices
outp :: [Int] -&amp;gt; Int -&amp;gt; [Char]
outp s k = concat (sl s k)
&lt;/pre&gt;
&lt;br /&gt;
A few examples:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;putStr (outp pr 6)

..++.+
.+...+
.+...+
.+...+
.....+
.+....
.+...+
.+...+
.....+
.....+
.+....
.+...+&lt;/pre&gt;
&lt;br /&gt;
immediately one sees that, with the exception 2 and 3, prime numbers have remainder 1 or 5 when divided by 6. For 7, the picture is &lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;putStr (outp pr 7)

..++.+.
+...+.+
...+.+.
..+....
.+.+...
..+...+
.+...+.
....+..
...+.+.
....+..
.+.+...
..+...+
.....+.
......+
...+.+.
..+.+..
.+.....
.......
.+...+.
....+.+
.......
..+.+..
...+...
..+...+&lt;/pre&gt;
&lt;br /&gt;
it's easy to see that "vertical" lines of "+", corresponding to a particular remainder are now (unsurprisingly) replaced with slopes. By changing the width of the picture, one can see how regular pattern changes its shape periodically&lt;br /&gt;
&lt;pre&gt;putStr (outp pr 23)

..++.+.+...+.+...+.+...
+.....+.+.....+...+.+..
.+.....+.....+.+.....+.
..+.+.....+...+.....+..
.....+...+.+...+.+...+.
............+...+.....+
.+.........+.+.....+...
..+...+.....+.....+.+..
.......+.+...+.+.......
....+...........+...+.+
...+.....+.+.........+.
....+.....+.....+.+....
.+...+.+.........+.....
........+...+.+...+....
.........+.....+.......
..+.+...+.....+.......+
.....+.....+...+.....+.
......+...+.......+....
.....+.+.........+.+...
..+...+.....+.......+..
.+.+...+...........+...&lt;/pre&gt;
&lt;br /&gt;
&lt;pre&gt;putStr (outp pr 24)

..++.+.+...+.+...+.+...+
.....+.+.....+...+.+...+
.....+.....+.+.....+...+
.+.....+...+.....+......
.+...+.+...+.+...+......
.......+...+.....+.+....
.....+.+.....+.....+...+
.....+.....+.+.........+
.+...+.+...........+....
.......+...+.+...+.....+
.+.........+.....+.....+
.....+.+.....+...+.+....
.....+.............+...+
.+...+.............+....
.+.........+.+...+.....+
.......+.....+.....+...+
.....+.......+...+......
.+.........+.+.........+
.+.....+...+.....+......
.+...+.+...+...........+
.......+...+.......+...+&lt;/pre&gt;
&lt;br /&gt;
One of the more striking examples is with twin primes:&lt;br /&gt;
&lt;pre&gt;putStr (outp twinp 6)

...+.+
.....+
.....+
......
.....+
......
.....+
......
......
.....+
......
.....+
......
......
......
......
.....+
.....+
......
......&lt;/pre&gt;
&lt;br /&gt;
Every pair of twin primes except for (3, 5) has a form (6*n - 1, 6*n + 1).&lt;br /&gt;
&lt;br /&gt;
As Gauss reportedly quipped (when refusing to work on the last Fermat's theorem): "number theory is full of problems whose difficulty is only surpassed by their uselessness".&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-8903228004689502384?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/8903228004689502384/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=8903228004689502384' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/8903228004689502384'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/8903228004689502384'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2012/03/riemann-hypothesis-diy.html' title='Riemann hypothesis, DIY'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-2148242483437445819</id><published>2011-12-24T21:50:00.000Z</published><updated>2012-05-11T20:53:41.874Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Cue a key</title><content type='html'>&lt;div dir="ltr" style="text-align: left;" trbidi="on"&gt;
&lt;div align="justify"&gt;
There is a typical problem with &lt;a href="http://en.wikipedia.org/wiki/Emacs"&gt;Emacs&lt;/a&gt; experienced by people frequently switching between different keyboard mappings, for example, to work with non ASCII languages: fundamental Emacs keyboard shortcuts (and one has to invoke them &lt;em&gt;a lot&lt;/em&gt; to use Emacs efficiently) all use ASCII keys. For example, when I want to save my work, while entering some Russian text, I have to do something like &lt;tt&gt;Alt-Space&lt;/tt&gt; (switch to the US keyboard layout) &lt;tt&gt;&lt;a href="http://www.gnu.org/software/emacs/manual/html_node/emacs/Save-Commands.html#index-C_002dx-s-845"&gt;Control-x-s&lt;/a&gt;&lt;/tt&gt; (a Emacs shortcut to save buffers) &lt;tt&gt;Alt-Space&lt;/tt&gt; (shift back to the Cyrillic keyboard layout). Switching out and back to a keyboard layout only to tap a short key sequence is really annoying.&lt;br /&gt;
&lt;br /&gt;
Two solutions are usually proposed:&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;Duplicate standard key sequences in other keyboard layouts. For example,&lt;br /&gt;
&lt;pre&gt;(global-set-key [(control ?ч ?ы)] 'save-some-buffers)
&lt;/pre&gt;
expression in &lt;tt&gt;.emacs&lt;/tt&gt; binds &lt;tt&gt;Control-ч-ы&lt;/tt&gt; to the same command as &lt;tt&gt;Control-x-s&lt;/tt&gt; is usually bound. This eliminates the need to switch layout, because &lt;tt&gt;ч&lt;/tt&gt;-&lt;tt&gt;x&lt;/tt&gt; (and &lt;tt&gt;ы&lt;/tt&gt;-&lt;tt&gt;s&lt;/tt&gt;) symbols are located on the same key (in &lt;a href="http://en.wikipedia.org/wiki/QWERTY"&gt;QWERTY&lt;/a&gt; and &lt;a href="http://en.wikipedia.org/wiki/JCUKEN"&gt;JCUKEN&lt;/a&gt; layouts respectively).&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;Another solution employs the fact that Emacs is &lt;a href="https://www.google.com/search?q=Emacs+is+a+great+operating+system.+If+only+it+had+a+decent+text+editor"&gt;a complete operating system&lt;/a&gt; and, therefore, has its own keyboard layout switching mechanism (bound to &lt;tt&gt;Control-\&lt;/tt&gt; by default). When this mechanism is used, Emacs re-interprets normals keys according to its internal layout, so that typing &lt;tt&gt;s&lt;/tt&gt; inserts &lt;tt&gt;ы&lt;/tt&gt; when in internal Russian mode, while all command sequences continue to work independently of layout. The mere idea of having &lt;em&gt;two&lt;/em&gt; independent layout switching mechanisms and two associated keyboard state indicators is clearly ugly beyond words (except for people who use Emacs as their &lt;tt&gt;/sbin/init&lt;/tt&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
Fortunately, there is another way:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;; Map Modifier-CyrillicLetter to the underlying Modifier-LatinLetter, so that
; control sequences can be used when keyboard mapping is changed outside of
; Emacs.
;
; For this to work correctly, .emacs must be encoded in the default coding
; system.
;
(mapcar* 
 (lambda (r e) ; R and E are matching Russian and English keysyms
   ; iterate over modifiers
   (mapc (lambda (mod)
    (define-key input-decode-map 
      (vector (list mod r)) (vector (list mod e))))
  '(control meta super hyper))
   ; finally, if Russian key maps nowhere, remap it to the English key without
   ; any modifiers
   (define-key local-function-key-map (vector r) (vector e)))
   "йцукенгшщзхъфывапролджэячсмитьбю"
   "qwertyuiop[]asdfghjkl;'zxcvbnm,.")
&lt;/pre&gt;
&lt;br /&gt;
(Inspired by a cryptic remark about "Translation Keymaps" in &lt;a href="http://vorotylo.livejournal.com/"&gt;vvv&lt;/a&gt;'s &lt;a href="https://github.com/vvv/dotfiles/blob/master/.emacs"&gt;.emacs&lt;/a&gt;.)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-2148242483437445819?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/2148242483437445819/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=2148242483437445819' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/2148242483437445819'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/2148242483437445819'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2011/12/cue-key.html' title='Cue a key'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4937279264799577372</id><published>2011-12-09T01:00:00.000Z</published><updated>2011-12-08T21:08:59.895Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>Unintentionally yours.</title><content type='html'>&lt;div dir="ltr" style="text-align: justify;" trbidi="on"&gt;&lt;script src="https://d3eoax9i5htok0.cloudfront.net/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;
    
&lt;/script&gt;&lt;br /&gt;
&lt;h2&gt;Extension.&lt;/h2&gt;&lt;br /&gt;
This post is about &lt;a href="http://en.wikipedia.org/wiki/Set_theory"&gt;set theory&lt;/a&gt;, which is a framework to reason about collections, elements and membership.&lt;br /&gt;
&lt;br /&gt;
We start with a informal and naïve outline, which is (very loosely) based on a &lt;a href="http://en.wikipedia.org/wiki/Von_Neumann-Bernays-G%C3%B6del_set_theory"&gt;Godel-Bernays&lt;/a&gt; version of set theory. This theory is about sets (collections) which contain elements, which can in turn be sets. When a set \(X\) contains an element \(t\), it is written \(t\in X\). &lt;br /&gt;
&lt;br /&gt;
First, set equality has to be defined:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;E0 &lt;a href="http://en.wikipedia.org/wiki/Axiom_of_extensionality"&gt;Axiom of extensionality&lt;/a&gt;&lt;/b&gt;:&lt;br /&gt;
$$X = Y \equiv (t \in X \equiv t \in Y)$$&lt;br /&gt;
(Here \(\equiv\) is a logical equivalence, pronounced "&lt;a href="http://en.wikipedia.org/wiki/Iff"&gt;if and only if&lt;/a&gt;".) This axiom means that sets are equal if and only if they have the same elements. (In this and following formulae, free variables are implicitly &lt;a href="http://en.wikipedia.org/wiki/Universal_quantification"&gt;universally quantified&lt;/a&gt;.)&lt;br /&gt;
&lt;br /&gt;
Subsets are defined by \(X \subseteq Y \equiv (t\in X \Rightarrow t\in Y)\), that is, X is a subset of Y when every element of X is also an element of Y. It's easy to check that \(X = Y \equiv (X\subseteq Y \wedge Y\subseteq X)\), where \(\wedge\) means "and".&lt;br /&gt;
&lt;br /&gt;
Next, a way to build new sets is needed:&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;E1 &lt;a href="http://en.wikipedia.org/wiki/Set-builder_notation"&gt;Axiom of (extensional) comprehension&lt;/a&gt;&lt;/b&gt;:&lt;br /&gt;
$$t \in \{u \mid P(u)\} \equiv P(t)$$&lt;br /&gt;
This axiom introduces a "set-builder notation" \(\{u \mid P(u) \}\) and states that \(\{u \mid P(u) \}\) is exactly the set of all \(t\) such that \(P(t)\) holds.&lt;br /&gt;
&lt;br /&gt;
Now, there is already enough machinery for two famous collections to be immediately constructed: &lt;b&gt;&lt;a href="http://en.wikipedia.org/wiki/Empty_set"&gt;empty set&lt;/a&gt;&lt;/b&gt;, \(\varnothing = \{t \mid false \}\), which contains no elements, and &lt;a href="http://en.wikipedia.org/wiki/Universe_(mathematics)"&gt;the collection of all sets&lt;/a&gt;: \(U = \{t \mid true \}\), which contains all possible elements.&lt;br /&gt;
&lt;br /&gt;
With these axioms, conventional set operations can be defined:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Singleton_(mathematics)"&gt;singleton&lt;/a&gt;: \(\{t\} = \{u\mid u = t\}\), for each \(t\) a singleton set \(\{t\}\) can be constructed that contains \(t\) as its only element. Note that \(t\in\{t\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Union_(set_theory)"&gt;union&lt;/a&gt;: \(X\cup Y = \{t\mid t \in X \vee t \in Y\}\) (\(\vee\) means "or")&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Intersection_(set_theory)"&gt;intersection&lt;/a&gt;: \(X\cap Y = \{t\mid t\in X \wedge t\in Y\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Complement_(set_theory)"&gt;complement&lt;/a&gt;: \(\complement X = \{t \mid t \notin X\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;(unordered) &lt;a href="http://en.wikipedia.org/wiki/Unordered_pair"&gt;pair&lt;/a&gt;: \(\{t,u\} = \{t\}\cup\{u\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Ordered_pair"&gt;ordered pair&lt;/a&gt;: \((t,u) = \{t, \{t, u\}\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="http://en.wikipedia.org/wiki/Power_set"&gt;power set&lt;/a&gt;: \(\mathfrak{P}(X) = \{t \mid t \subseteq X\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
From here, one can build hierarchical sets, representing all traditional mathematical structures, starting with natural numbers: &lt;br /&gt;
&lt;br /&gt;
$$0 = \varnothing, 1 = \{0\}, 2 = \{0, 1\}, \ldots n + 1 = \{0, \ldots, n\}, \ldots$$&lt;br /&gt;
&lt;br /&gt;
then integers, rationals, reals, &lt;i&gt;&amp;amp;c.&lt;/i&gt;, adding more axioms (of &lt;a href="http://en.wikipedia.org/wiki/Axiom_of_infinity"&gt;infinity&lt;/a&gt;, of &lt;a href="http://en.wikipedia.org/wiki/Axiom_of_regularity"&gt;foundation&lt;/a&gt;, of &lt;a href="http://en.wikipedia.org/wiki/Axiom_schema_of_replacement"&gt;replacement&lt;/a&gt;, &lt;i&gt;&amp;amp;c&lt;/i&gt;.) along the way.&lt;br /&gt;
&lt;br /&gt;
It was discovered quite early that this system is not entirely satisfactory. First defect is that it is impossible to have elements which are not sets themselves. For example, one would like to talk about a "set of all inhabited planets in the Solar system". Elements of this set (planets) are not sets, they are called &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Urelement"&gt;ur-elements&lt;/a&gt;&lt;/i&gt;. Unfortunately, the axiom of extensionality makes all ur-elements equal to the empty set. Note, that this indicates that the axiom of extensionality doesn't work well with sets that have very few (none) elements. This was never considered a problem, because all sets of interest to mathematics can be constructed without ur-elements.&lt;br /&gt;
&lt;br /&gt;
Another, more serious drawback, arises in the area of very large sets: existence of a set \(\{t\mid t\notin t\}\) directly leads to a contradiction known as &lt;a href="http://en.wikipedia.org/wiki/Russell's_paradox"&gt;Russel's paradox&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Among several methods to deal with this, one separates sets into two types: "smaller" collections which are continued to be called "sets" and "proper classes", which are collections so large that they cannot be a member of any collection. Axiom of comprehension is carefully modified so that set-builder never produces a collection having some class as its element. In this setup Russel's paradox becomes a theorem: \(\{t\mid t\notin t\}\) is a proper class.&lt;br /&gt;
&lt;br /&gt;
&lt;h2&gt;Intention.&lt;/h2&gt;&lt;br /&gt;
The axiom of extensionality states that sets are equal when they &lt;em&gt;contain&lt;/em&gt; the same elements. What would happen, if set theory were based on a dual notion of &lt;em&gt;intentional equality&lt;/em&gt; (which will be denoted by \(\sim\) to tell it from extensional one), where sets are equal when they are &lt;em&gt;contained&lt;/em&gt; in the same collections?&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;I0 Axiom of intensionality&lt;/b&gt;:&lt;br /&gt;
$$X \sim Y \equiv (X \in t \equiv Y\in t)$$&lt;br /&gt;
This looks bizarre: for any "normal" set \(X\) a collection of all sets containing \(X\) as element is unmanageably huge. But as a matter of fact, intentional equality is much older than extensional, it is variously known as &lt;em&gt;Leibniz's law&lt;/em&gt;, &lt;a href="http://en.wikipedia.org/wiki/Identity_of_indiscernibles"&gt;identity of indiscernibles&lt;/a&gt; and, in less enlightened age, as &lt;a href="http://en.wikipedia.org/wiki/Duck_typing"&gt;duck typing&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
There is a nice symmetry: while intensional equality myopically confuses small sets (ur-elements), extensional equality cannot tell very large collections (proper classes) from each other, because they are not members of anything and, therefore, intentionally equal.&lt;br /&gt;
&lt;br /&gt;
The whole extensional theory buildup can be mirrored easily by moving things around \(\in\) sign:&lt;br /&gt;
&lt;br /&gt;
Intensional subsets: \(X \unlhd Y \equiv (X\in t \Rightarrow Y\in t)\)&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;I1 Axiom of intensional comprehension (incomprehension)&lt;/b&gt;:&lt;br /&gt;
$$[u \mid P(u)]\in t \equiv P(t)$$&lt;br /&gt;
&lt;br /&gt;
And associated operations:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;uniqum (or should it have been "s-&lt;i&gt;ex&lt;/i&gt;-gleton?): \([t] = [u\mid u \sim t]\), note that \([t]\in t\).&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional union: \(X\triangledown Y = [t\mid X \in t \vee Y \in t]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional intersection: \(X\triangle Y = [t\mid X \in t \wedge Y \in t]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional complement: \(\Game X = [t \mid X \notin t]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional pair: \([t,u] = [t]\triangledown [u]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional ordered pair: \(&amp;lt;t,u&amp;gt; = [t, [t, u]]\)&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;intentional power set: \(\mathfrak{J}(X) = [t \mid X \unlhd t\}\)&lt;br /&gt;
&lt;/li&gt;
&lt;/ul&gt;&lt;br /&gt;
What do all these things &lt;em&gt;mean&lt;/em&gt;? In extensional world, a set is a container, where elements are stored. In intensional world, a set is a &lt;em&gt;property&lt;/em&gt;, which other sets might or might not enjoy. If \(t\) has property \(P\), it is written as \(t\in P\). In the traditional notation, \(P\) is called a &lt;em&gt;predicate&lt;/em&gt; and \(t\in P\) is written as \(P(t)\). The axiom of intentional equality claims that sets are equal when they have exactly the same properties (quite natural, right?). \(X\) is an intentional subset of \(Y\) when \(Y\) has all properties of \(X\) and perhaps some more (this looks like a nice way to express &lt;a href="http://en.wikipedia.org/wiki/Liskov_substitution_principle"&gt;LSP&lt;/a&gt;). Intentional comprehension \([u \mid P(u)]\) is a set having exactly all properties \(t\) for which \(P(t)\) holds and no other properties. Intentional union of two sets is a set having properties of either and their intentional intersection is a set having properties of both, &lt;i&gt;&amp;amp;c&lt;/i&gt;. Uniqum \([P]\) is &lt;em&gt;the&lt;/em&gt; set that has property \(P\) and no other properties.&lt;br /&gt;
&lt;br /&gt;
Because intensional theory is a perfect dual of extensional nothing interesting is obtained by repeating extensional construction, for example, by building "intensional natural numbers" as &lt;br /&gt;
&lt;br /&gt;
$$0' = U, 1' = [0'], 2' = [0', 1'], \ldots (n + 1)' = [0', \ldots, n'], \ldots$$&lt;br /&gt;
&lt;br /&gt;
What is more interesting, is how intensional and extensional twins meet. With some filial affection it seems:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;by uniqum property \([\varnothing] \in\varnothing\), which contradicts the definition of \(\varnothing\), also&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;set \([t\mid false]\) is not a member of any set (perhaps it's a proper class) and set \([t\mid true]\) is a member of every set, which is strange;&lt;br /&gt;
&lt;/li&gt;
&lt;li&gt;a set of which a singleton can be formed has very shallow intentional structure. Indeed:&lt;br /&gt;
&lt;table border="0" bordercolor="#ffffff" style="background-color:" cellpadding="3" cellspacing="3"&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x \unlhd y\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\equiv\)&lt;/td&gt;&lt;td&gt;{ definition of intensional subset }&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x\in t \Rightarrow y\in t\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\Rightarrow\)&lt;/td&gt;&lt;td&gt;{ substitute \(\{x\}\) for \(t\)}&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x\in \{x\} \Rightarrow y\in \{x\}\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\equiv\)&lt;/td&gt;&lt;td&gt;{ \(x\in \{x\}\) is true by the singleton property, &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Modus_ponens"&gt;modus ponens&lt;/a&gt;&lt;/i&gt; }&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(y\in \{x\}\)&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;\(\equiv\)&lt;/td&gt;&lt;td&gt;{ the singleton property, again }&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;td&gt;\(x = y\)&lt;/td&gt;&lt;/tr&gt;
&lt;/table&gt;&lt;/ul&gt;To get rid of contradictions and to allow intensional and extensional sets to co-exist peacefully, domains on which singleton and uniqum operations are defined must be narrowed.  To be continued. &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4937279264799577372?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4937279264799577372/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4937279264799577372' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4937279264799577372'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4937279264799577372'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2011/11/unintentionally-yours.html' title='Unintentionally yours.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1841531294338939775</id><published>2010-12-29T19:42:00.002Z</published><updated>2010-12-29T19:44:23.574Z</updated><title type='text'>From the traveller diary.</title><content type='html'>Note to oneself: general anaesthesia is a very efficient cure for jet lag.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1841531294338939775?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1841531294338939775/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1841531294338939775' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1841531294338939775'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1841531294338939775'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/12/traveller-diary.html' title='From the traveller diary.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-5216923215068280821</id><published>2010-02-18T19:20:00.000Z</published><updated>2010-02-18T19:20:02.520Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'></title><content type='html'>An obscure generalisation: a redundancy domain should be transversal (better yet, orthogonal) to a potential failure vector. Hello, &lt;a href="http://en.wikipedia.org/wiki/Narendra_Karmarkar"&gt;Karmarkar&lt;/a&gt;!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-5216923215068280821?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/5216923215068280821/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=5216923215068280821' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5216923215068280821'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5216923215068280821'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/02/obscure-generalisation-redundancy.html' title=''/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-9082152881386341264</id><published>2010-02-04T21:20:00.004Z</published><updated>2010-03-10T20:50:23.805Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>The Hunt for Addi(c)tive Monster 2.</title><content type='html'>&lt;div style="text-align: justify;"&gt;
In the &lt;a href="http://www.cofault.com/2010/01/hunt-for-addictive-monster.html"&gt;previous post&lt;/a&gt;, we were looking for&amp;nbsp;&lt;i&gt;a monster&lt;/i&gt;—a nonlinear additive function. We found that such a function is extremely pathological: it is nowhere locally monotone, nowhere continuous and nowhere locally bounded. Worse than that, it's easy to prove that the graph of a monster is &lt;a href="http://en.wikipedia.org/wiki/Dense_set"&gt;dense&lt;/a&gt; in &lt;img border="0" src="http://l.wordpress.com/latex.php?latex={{\mathbb{R} \times \mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, that is, for every &lt;i&gt;x&lt;/i&gt; and &lt;i&gt;y&lt;/i&gt;, an arbitrary neighborhood of &lt;i&gt;x&lt;/i&gt; contains a point that monster sends arbitrarily close to &lt;i&gt;y&lt;/i&gt;.&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;
Recall &lt;a href="http://www.cofault.com/2010/01/hunt-for-addictive-monster.html#construction-0"&gt;our attempt&lt;/a&gt; to construct a monster. Any additive function is linear on any &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set and is fully determined on this set by a value it has in any single of its points. Our Direchlet function derived monster failed (or rather fell) because the slopes an additive function has on different &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-sets are not independent. Indeed, given that &lt;i&gt;f&lt;/i&gt; has a slope &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{k_1}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; on a &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot\alpha_1}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; and a slope &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{k_2}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; on a &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot\alpha_2}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, it has to have a slope &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{k_1 %2B k_2}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; on a &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot(\alpha_1 %2B \alpha_2)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;. This shows a way to construct a monster: one has to find a collection &lt;i&gt;B&lt;/i&gt; of real numbers &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{r_1, r_2, \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; such that (i) every real number can be represented as a sum &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1\cdot r_1 %2B q_2\cdot r_2 %2B \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;, with rational coefficients &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1, q_2, \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; of which only finite number is non-zero (so that the sum is defined) and (ii) that such representation is unique. Then one can select arbitrary values on elements of &lt;i&gt;B&lt;/i&gt; and take moster's value on &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1\cdot r_1 %2b q_2\cdot r_2 %2b \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; to be &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q_1\cdot f(r_1) %2b q_2\cdot f(r_2) %2b \ldots}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, which is well-defined thanks to (ii).&lt;br /&gt;
&lt;br /&gt;
Looks familiar? It should be: the definition of &lt;i&gt;B&lt;/i&gt; is exactly the definition of &lt;a href="http://en.wikipedia.org/wiki/Basis_(linear_algebra)"&gt;a basis&lt;/a&gt; of a vector space. Real numbers can be added to each other and multiplied by rationals and, therefore, form a vector space over&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;. This space is very different from a usual one-dimensional vector space real numbers form over&amp;nbsp;&lt;img src="http://l.wordpress.com/latex.php?latex={{\mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; (&lt;i&gt;i.e.&lt;/i&gt;, over themselves).&lt;br /&gt;
&lt;br /&gt;
After a streak of bad and unlikely properties that a monster has, we now got something positive: a monster exists if and only if&amp;nbsp;&lt;img src="http://l.wordpress.com/latex.php?latex={{\mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;as a vector space over&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;has a basis. Does it?&lt;br /&gt;
&lt;br /&gt;
But of course. Any vector space has a basis—this is a general theorem almost immediately following from the &lt;a href="http://en.wikipedia.org/wiki/Zorn's_lemma"&gt;Zorn's lemma&lt;/a&gt;. The basis we are looking for even got a name of its own: &lt;a href="http://mathworld.wolfram.com/HamelBasis.html"&gt;&lt;i&gt;Hamel basis&lt;/i&gt;&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
At last we stumbled across the whole family on monsters. Specifically, there exists a set &lt;img src="http://l.wordpress.com/latex.php?latex={{B \subset \mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;and a function &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q : \mathbb{R}\times B \rightarrow \mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; such that every real number r can be uniquely represented as&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{r = \displaystyle\sum_{b\in B}q(r, b)\cdot b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/div&gt;
&lt;br /&gt;
where only finite number of &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q(r, b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;are non-zero for a given &lt;i&gt;r&lt;/i&gt;. From this it immediately follows that &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{q(r_1 %2b r_2, b) = q(r_1, b) %2b q(r_2, b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;.&lt;br /&gt;
&lt;br /&gt;
Take an arbitrary function &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0 : B \rightarrow \mathbb{R}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, and define&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r) = \displaystyle\sum_{b\in B} f_0(b)\cdot q(r, b)\cdot b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;&lt;/div&gt;
Now,&lt;br /&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r_1) %2b f(r_2) = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\displaystyle\sum_{b\in B} f_0(b)\cdot q(r_1, b)\cdot b %2b \displaystyle\sum_{b\in B} f_0(b)\cdot q(r_2, b)\cdot b = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\displaystyle\sum_{b\in B} f_0(b)\cdot\left(q(r_1, b) %2b q(r_2, b)\right)\cdot b = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;div style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\displaystyle\sum_{b\in B} f_0(b)\cdot q(r_1 %2b r_2, b) \cdot b = }}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r_1 %2b r_2)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&lt;/blockquote&gt;
that is,&amp;nbsp;&lt;i&gt;f&lt;/i&gt; is additive. Intuitively,&amp;nbsp;&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0(b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; is a slope &lt;i&gt;f&lt;/i&gt; has at the &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;-set &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{\mathbb{Q}\cdot b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;. &lt;i&gt;f&lt;/i&gt; is linear if and only if &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt; is a constant function, in all other cases &lt;i&gt;f&lt;/i&gt; is a monster. If one takes &lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f_0 : b \mapsto 1/b}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;, then&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="center" src="http://l.wordpress.com/latex.php?latex={{f(r) = \displaystyle\sum_{b\in B} q(r, b)}}&amp;amp;bg=ffffff&amp;amp;fg=000000&amp;amp;s=0" /&gt;&amp;nbsp;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
is an especially weird monster function: it takes only rational values!&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
Note that almost all additive functions are, after all, monsters—only very small sub-set of them is linear.&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-9082152881386341264?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/9082152881386341264/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=9082152881386341264' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/9082152881386341264'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/9082152881386341264'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/02/hunt-for-addictive-monster-2.html' title='The Hunt for Addi(c)tive Monster 2.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-7287619472314268722</id><published>2010-01-12T15:12:00.042Z</published><updated>2010-02-04T21:21:28.618Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>The Hunt for Addi(c)tive Monster</title><content type='html'>&lt;div style="text-align: justify;"&gt;
&lt;div class="separator" style="clear: both; text-align: justify;"&gt;
This is another spurious post about mathematics that happened instead
of something more useful. Let's talk about one of the most common
mathematical objects: a &lt;a href="http://en.wikipedia.org/wiki/Function_%28mathematics%29"&gt;function&lt;/a&gt;&amp;nbsp;that maps&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Real_number"&gt;real numbers&lt;/a&gt; (&lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;) to real numbers. We shall call such a function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; &lt;i&gt;additive&lt;/i&gt; &lt;a href="http://en.wikipedia.org/wiki/Iff"&gt;iff&lt;/a&gt;&amp;nbsp;for any real &lt;i&gt;x&lt;/i&gt; and &lt;i&gt;y&lt;/i&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" alt="f(a + b) = f(a) + f(b)" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizefx%2520%2520y%2520%2520fx%2520%2520fy.gif" /&gt;
&lt;br /&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
This is a natural and simple condition. Well-known examples of additive functions are provided by &lt;i&gt;linear&lt;/i&gt; functions &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520x%2520mapsto%2520k%2520cdot%2520x.gif" /&gt;, where &lt;i&gt;k&lt;/i&gt; is called &lt;i&gt;a slope&lt;/i&gt;.
Are there other, non-linear additive functions? And if so, how do they
look like? A bit of thinking convinces one that a non-linear additive
function is not trivial to find. In fact, as we shall show below,
should such a function exist, it would exhibit extremely weird
features. Hence, we shall call a non-linear additive function &lt;i&gt;a monster&lt;/i&gt;.
In the following, some properties that a monster function has to
possess are investigated, until a monster is cornered either out of
existence or into an example. Out of misplaced spite we shall use &lt;a href="http://en.wikipedia.org/wiki/%28%CE%B5,_%CE%B4%29-definition_of_limit"&gt;&lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon-delta.gif" /&gt; technique&lt;/a&gt; in some proofs.&lt;br /&gt;
&lt;br /&gt;
First, some trivial remarks about the collection of all additive functions (which will be denoted &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizemathsfAdd.gif" /&gt;).&lt;br /&gt;
&lt;br /&gt;
If &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt;, &lt;img align="middle" alt="g : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeg%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt;&amp;nbsp;are two additive functions and &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizealpha%2520in%2520mathbbR.gif" /&gt; — an arbitrary real number, then &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizefg.gif" /&gt;, &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsize-f.gif" /&gt; and &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizealpha%2520cdot%2520f.gif" /&gt; are additive. This means that additive functions form a &lt;a href="http://en.wikipedia.org/wiki/Vector_space"&gt;vector space&lt;/a&gt; over field &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt; with constant zero additive function as a &lt;a href="http://en.wikipedia.org/wiki/Zero_vector"&gt;zero vector&lt;/a&gt;. This vector space is a sub-space of a vector space of all functions from &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt; to &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;. Product of two additive functions is not in general additive (when it is?), but their composition is:&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%252520circ%252520gx%252520%252520y%252520%252520fgx%252520%25252.gif" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Unfortunately, composition is not compatible with scalars (&lt;i&gt;i.e.&lt;/i&gt;, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizealpha%252520cdot%252520f%252520circ%252520beta%252520cdot%2525.gif" /&gt;), and additive functions are not an&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Algebra_over_a_field"&gt;algebra over a field&lt;/a&gt;&amp;nbsp;&lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;, but see below.&lt;br /&gt;
&lt;br /&gt;
Looking at an individual additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt;, it's easy to see that even it is not clear that it must be linear everywhere, there are some subsets of &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbR.gif" /&gt;&amp;nbsp;on which is obviously has to be linear:&lt;br /&gt;
&lt;br /&gt;
For any real number &lt;i&gt;x&lt;/i&gt; and for any natural number &lt;i&gt;n&lt;/i&gt;,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefncdot%252520x%252520%252520fx%252520%252520cdots%252520%252520x.gif" /&gt;
&lt;/div&gt;
&lt;br /&gt;
that is, restriction of &lt;i&gt;f&lt;/i&gt; to any subset &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizexcdot%2520mathbbN%2520subset%2520mathbbR.gif" /&gt; is linear and in particular, &lt;i&gt;f&lt;/i&gt; is linear when restricted to the natural numbers. Specifically, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizef0%252520%252520f2%252520cdot%2525200%252520%2525202%252520cdot%25.gif" /&gt;, from this&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizef-x%252520%252520f-x%252520%252520fx%252520-%252520fx%252520%25252.gif" /&gt;&lt;/div&gt;
&lt;br /&gt;
Similarly,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeffrac1n%252520cdot%252520x%252520%252520frac1n%252520cdot%2525.gif" /&gt;&lt;/div&gt;
&lt;br /&gt;
Combining these results, for any rational number &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeq%2520%2520fracnm%2520in%2520mathbbQ.gif" /&gt;,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefq%252520cdot%252520x%252520%252520ffracnm%252520cdot%252520x%25.gif" /&gt;&lt;/div&gt;
&lt;br /&gt;
That is, &lt;i&gt;f&lt;/i&gt; is linear when restricted to any subset of the form &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizex%2520cdot%2520mathbbQ%2520subset%2520mathbbR.gif" /&gt;. We shall call such subset &lt;i&gt;a &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-set&lt;/i&gt;.&lt;br /&gt;
&lt;br /&gt;
Notice that we just proved that composition of linear functions is
compatible with multiplication on rational scalars (see above), so that
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizemathsfAdd.gif" /&gt; is an algebra over &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;.&lt;br /&gt;
&lt;br /&gt;
Having briefly looked over the landscape of &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizemathsfAdd.gif" /&gt;,
let's start converging on our prey. How bad a monster function must be?
A linear function has all the good qualities one might wish for: it is &lt;a href="http://en.wikipedia.org/wiki/Monotonic_function"&gt;monotonic&lt;/a&gt;,&amp;nbsp;&lt;a href="http://en.wikipedia.org/wiki/Continuous_function"&gt;continuous&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Differentiable_function"&gt;differentiable&lt;/a&gt;, &lt;a href="http://en.wikipedia.org/wiki/Smooth_function"&gt;smooth&lt;/a&gt;,
it's even... linear. Which of these it enjoys together with a monster?
It's intuitively very unlikely that an additive, but non-linear
function might happen to be differentiable, so let's start with
checking continuity.&lt;br /&gt;
&lt;br /&gt;
Statement 0. If an additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; is continuous at point &lt;i&gt;x&lt;/i&gt;, then&amp;nbsp;&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefx%2520%2520x%2520cdot%2520f1.gif" /&gt;.&lt;br /&gt;
&lt;blockquote&gt;
Indeed,&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizebeginarraycclfx%252520%252520%252520%252520%252520%252520mboxt.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;br /&gt;
That is, an additive function is linear everywhere it is continuous.
This means that a monster must be&amp;nbsp;discontinuous&amp;nbsp;at least in
one point. Note that linear functions are precisely everywhere
continuous additive functions. Can a monster function
be&amp;nbsp;discontinuous&amp;nbsp;in a single point? Or, even, can it be
continuous &lt;i&gt;somewhere&lt;/i&gt;? It is easy to show that property of additivity constrains structure of sets on which function is continuous severely:&lt;br /&gt;
&lt;br /&gt;
Statement 1. If an additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; is continuous at point &lt;i&gt;x&lt;/i&gt;, it is linear.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;
Take an arbitrary non-zero point &lt;i&gt;y&lt;/i&gt;. By statement 0,&amp;nbsp;&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizefx%2520%2520x%2520cdot%2520f1.gif" /&gt;. By definition of continuity at &lt;i&gt;x&lt;/i&gt;,&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeforall%252520epsilon%252520%2525200%252520rightarrow%252520e.gif" /&gt;&amp;nbsp;,&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
For any natural &lt;i&gt;n&lt;/i&gt;, take&amp;nbsp;&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon%2520%2520frac1n%2520%25200.gif" /&gt;&amp;nbsp;and find a rational number &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt;, such that &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize%252520q_ncdoty%252520-%252520x%252520%252520%252520mindelta%252.gif" /&gt;. Such &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; always exists due to density of rationals. By choice of &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; we have:&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize-frac1n%252520%252520q_n%252520cdoty%252520-%252520x%252520%2525.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
and by the &lt;a href="http://en.wikipedia.org/wiki/Squeeze_theorem"&gt;sandwich theorem&lt;/a&gt;, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; converges:&amp;nbsp;&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizelim_ntoinftyq_n%2520%2520fracxy.gif" /&gt;. Now, again, by choice of &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt;: &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize%252520q_n%252520cdot%252520y%252520-%252520x%252520%252520%252520.gif" /&gt;, so &lt;i&gt;y&lt;/i&gt;&lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeq_n.gif" /&gt; satisfies the condition on &lt;i&gt;x'&lt;/i&gt; above and &lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" alt="\epsilon = \frac1n &amp;gt; |f(q_n \cdot y) - f(x)| = |q_n \cdot f(y) - x \cdot f(1)|" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon%252520%252520frac1n%252520%252520fq_n%252520cdot%25252.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;br /&gt;&lt;/div&gt;
Taking the (obviously existing)&amp;nbsp;limits of both sides of this inequality,&amp;nbsp;one gets&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;img align="middle" alt="f(y) = \frac{x \cdot f(1)}{\lim_{n\to\infty}q_n} = \frac{x \cdot f(1)}{x/y} = y \cdot f(1)" border="0" src="http://linuxhacker.ru/~nikita/images/add/y%2520%2520y%2520cdot%2520f1.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
The case of y being 0 is trivial.&lt;/blockquote&gt;
Oh. A monster function cannot be continuous even at a single point—it
is discontinuous everywhere. Additive functions are divided into two
separated classes: nice, everywhere continuous linear functions and
&amp;nbsp;unseemly, everywhere discontinuous monsters. (We still don't know
whether the latter class is populated, though.) Our expectations of
capturing a monster and placing a trophy in a hall must be adjusted:
even if we prove that a monster exists and construct it, an idea of
drawing its &lt;a href="http://en.wikipedia.org/wiki/Graph_of_a_function"&gt;graph&lt;/a&gt; must be abandoned—it's too ugly to be depicted.&lt;br /&gt;
&lt;br /&gt;
&lt;a href="" name="construction-0"&gt;&lt;/a&gt;Let's think for a moment how a monster might look like. Every additive function is linear on any &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-set. If it is linear with the same slope on all &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-sets—it is linear. A monster must have different slopes for at least some of &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-sets. In the simplest case there is a single &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-set
with a slope different from the others. There is a famous function (a
freshman nightmare and examiner delight) immediately coming into a
mind: the &lt;a href="http://en.wikipedia.org/wiki/Nowhere_continuous_function"&gt;Dirichlet function&lt;/a&gt;, &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeD%2520%2520mathbbR%2520rightarrow%2520mathbbZ_2.gif" /&gt;, equal 1 on rationals and 0 on irrationals. The function &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsized%2520%2520x%2520mapsto%2520x%2520cdot%2520Dx.gif" /&gt;&amp;nbsp;is
identity (and hence linear) when restricted to rationals and is
constant zero (again linear) when restricted to irrationals. Looks
promising? Unfortunately,&lt;br /&gt;
&lt;br /&gt;
&lt;div style="text-align: center;"&gt;
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsize0%252520%252520d1%252520%252520pi%252520neq%252520d1%252520%252520.gif" /&gt;
&lt;/div&gt;
&lt;br /&gt;
Also, &lt;i&gt;d&lt;/i&gt; is continuous at 0 and thus disqualified
from&amp;nbsp;monstrousness&amp;nbsp;by statement 1. This shot into darkness
missed. At at least we now see that not only monster must have
different slopes at different &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizemathbbQ.gif" /&gt;-sets, but these slopes must be selected to be consistent with addition.&lt;br /&gt;
&lt;br /&gt;
Let's return to monster properties. A monster function is discontinuous everywhere, but how badly is it discontinuous? &lt;i&gt;E.g.&lt;/i&gt;, a function is &lt;a href="http://en.wikipedia.org/wiki/Local_boundedness"&gt;locally bounded&lt;/a&gt;
at every point where it is continuous. A monster is continuous nowhere,
but is it still locally bounded anywhere or somewhere? In a way similar
to statement 1 it's easy to prove the&lt;br /&gt;
&lt;br /&gt;
Statement 2. If an additive function &lt;img align="middle" alt="f : \mathbb{R} \rightarrow \mathbb{R}" border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizef%2520%2520mathbbR%2520rightarrow%2520mathbbR.gif" /&gt; is bounded on any segment [&lt;i&gt;a&lt;/i&gt;, &lt;i&gt;b&lt;/i&gt;], &lt;i&gt;a &amp;lt; b&lt;/i&gt;, then it is linear.&lt;br /&gt;
&lt;blockquote&gt;
First, by using that &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizef-x%2520%2520-fx.gif" /&gt;, &amp;nbsp;and restricting segment if necessary, one can assume that &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsize0%2520%2520a%2520%2520b.gif" /&gt;, and &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizeforall%252520x%252520in%252520a%252520b%252520rightarrow%25252.gif" /&gt;.&lt;/blockquote&gt;
&lt;blockquote&gt;
Let's prove that &lt;i&gt;f&lt;/i&gt; is continuous at 0, then it will be linear by the statement 1. For arbitrary &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon%2520%25200.gif" /&gt;, let's select &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizedelta.gif" /&gt;, such that &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsize0%2520%2520delta%2520%2520fracaCcdotepsilon.gif" /&gt;&amp;nbsp;(this choice is a typical magician hat trick of &lt;img border="0" src="http://linuxhacker.ru/~nikita/images/add/normalsizeepsilon-delta.gif" /&gt; proofs). For arbitrary &lt;i&gt;x&lt;/i&gt; from the &lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizedelta.gif" /&gt;-vicinity of 0 there is always a rational &lt;i&gt;q&lt;/i&gt;, such that &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizea%2520%2520qcdot%2520x%2520%2520b.gif" /&gt;. For such &lt;i&gt;q&lt;/i&gt; we have:&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;div style="text-align: center;"&gt;
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizeq%252520%252520fracax%252520%252520fracadelta%252520%252520fra.gif" /&gt;&lt;/div&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
on the other hand, we have:&lt;br /&gt;
&lt;blockquote&gt;
&lt;img src="http://linuxhacker.ru/~nikita/images/add/normalsizebeginarrayrclfx%252520%252520%252520%252520ffracqcdot%252520.gif" /&gt;&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;blockquote&gt;
establishing that &lt;i&gt;f&lt;/i&gt; is continuous at 0.&lt;/blockquote&gt;
This indicates that a monster is not just a bad function, it's a very
bad function, that takes arbitrarily large absolute values in
arbitrarily small segments. Too bad. As a byproduct, a monster cannot
be monotonic on any segment, because a function monotonic on [&lt;i&gt;a&lt;/i&gt;, &lt;i&gt;b&lt;/i&gt;] is bounded there: &lt;img align="middle" src="http://linuxhacker.ru/~nikita/images/add/normalsizefa%2520leq%2520fx%2520leq%2520fb.gif" /&gt;&amp;nbsp;(for increasing function, similarly for decreasing).&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.cofault.com/2010/02/hunt-for-addictive-monster-2.html"&gt;continued&lt;/a&gt;.&lt;b&gt;]&lt;/b&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-7287619472314268722?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/7287619472314268722/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=7287619472314268722' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/7287619472314268722'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/7287619472314268722'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2010/01/hunt-for-addictive-monster.html' title='The Hunt for Addi(c)tive Monster'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4071479957601685895</id><published>2009-09-20T14:33:00.002Z</published><updated>2009-09-20T14:40:17.241Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><title type='text'>To the Lustre Group people</title><content type='html'>&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://picasaweb.google.com/danilov/A4#5382922663089670802" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://lh4.ggpht.com/_QCNNSTdukHs/SrP7pGLcCpI/AAAAAAAAJPM/5JgnpmiXZRo/s320/CIMG0076.JPG" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
With the best wishes to Sun^WOracle, and &lt;i&gt;sapienti &lt;a href="http://wiki.lustre.org/images/6/66/CLIO-TOI.pdf"&gt;sat&lt;/a&gt;&lt;/i&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4071479957601685895?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4071479957601685895/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4071479957601685895' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4071479957601685895'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4071479957601685895'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/09/to-lustre-group-people.html' title='To the Lustre Group people'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://lh4.ggpht.com/_QCNNSTdukHs/SrP7pGLcCpI/AAAAAAAAJPM/5JgnpmiXZRo/s72-c/CIMG0076.JPG' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4955873462769947276</id><published>2009-08-21T11:07:00.015Z</published><updated>2009-08-21T13:25:24.403Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>a trivial exercise.</title><content type='html'>&lt;div style="text-align: justify;"&gt;Let's find a sum&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=6156d5fba9e2bc73ae25f65e9922d4f0"&gt;&lt;/center&gt;&lt;br&gt;

There is a well-know standard way, that I managed to recall eventually. Given that&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;IMG SRC="http://snappy.at.org/~cola/tex2img/image.php?id=aedff0aa4c12833656b0d7be385d2088" STYLE="vertical-align: middle;" ALT="$${1 \over n(n+2)} = {1 \over 2}\cdot \left({1\over n} - {1\over n+2}\right)$$" HEIGHT="51" WIDTH="259"&gt;&lt;/center&gt;&lt;br&gt;

the sum can be re-written as&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=f658ebfb6b0015852558bacf8b3c00bc" style="vertical-align: middle;" alt="$$\sum_{n=1}^\infty {1\over{n(n+2)}} = \sum_{n=1}^\infty {1 \over 2}\left({1\over n} - {1\over n+2}\right) = {1\over 2}\left({1\over 1} - {1\over 3} + {1\over 2} - {1\over 4} + {1\over 3} - {1\over 5} + {1\over 4} - {1\over 6} \cdots\right)$$" height="58" width="725" /&gt;&lt;/center&gt;&lt;br&gt;

with almost all terms canceling each other, leaving&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=367cfc1e89df5edaa1eab5127a97aba8" style="vertical-align: middle;" alt="$$\sum_{n=1}^\infty {1\over{n(n+2)}} = {1\over 2}\left(1 + {1\over 2}\right) = {3\over 4}$$" height="58" width="285" /&gt;&lt;/center&gt;&lt;br&gt;

While this is easy to check, very little help is given on understanding how to arrive to the solution in the first place. Indeed, the first (and crucial) step is a rabbit pulled &lt;span style="font-style: italic;"&gt;sans motif&lt;/span&gt; out of a conjurer hat. The solution, fortunately, can be found in a more systematic fashion, by a relatively generic method. Enter &lt;a href="http://en.wikipedia.org/wiki/Generating_function"&gt;generating functions&lt;/a&gt;.&lt;br&gt;&lt;br&gt;

First, introduce a function&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=d00d8c3c9f58dfcad4996ada9a7ed186" style="vertical-align: middle;" alt="$$f(t) = \sum_{n=1}^\infty {t^{n + 1}\over n}$$" height="58" width="140" /&gt;&lt;/center&gt;&lt;br&gt;

The series on the right converge absolutely when |t| &lt; 1, so one can define&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;IMG SRC="http://snappy.at.org/~cola/tex2img/image.php?id=5191d5a25430c7bac0bf6e83016e832d" STYLE="vertical-align: middle;" ALT="$$g(t) = \int f(t) dt = \int \sum_{n=1}^\infty {t^{n + 1}\over n} = \sum_{n=1}^\infty \int {t^{n + 1}\over n} = \sum_{n=1}^\infty {t^{n + 2}\over {n(n+2)}} + C$$" HEIGHT="58" WIDTH="589"&gt;&lt;/center&gt;&lt;br&gt;

with the sum in question being&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=7240522421194f419404885930786b43" style="vertical-align: middle;" alt="$$\sum_{n=1}^\infty {1\over{n(n+2)}} = g(1) - C = g(1) - g(0)$$" height="58" width="349" /&gt;&lt;/center&gt;&lt;br&gt;

Definition of the &lt;span style="font-style: italic;"&gt;g&lt;/span&gt; function follows immediately from the form of the original sum, and there is a limited set of operations (integration, differentiation, &lt;span style="font-style: italic;"&gt;etc&lt;/span&gt;.) applicable to &lt;span style="font-style: italic;"&gt;g&lt;/span&gt; to produce &lt;span style="font-style: italic;"&gt;f&lt;/span&gt;.&lt;br&gt;&lt;br&gt;

The rest is more or less automatic. Note that&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=4b213b85278134477d35774075284944" style="vertical-align: middle;" alt="$$- ln(1 - t) = t + {t^2\over 2} + {t^3\over 3} + \cdots$$" height="47" width="271" /&gt;&lt;/center&gt;&lt;br&gt;

so that&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;IMG SRC="http://snappy.at.org/~cola/tex2img/image.php?id=7453e9ff6f54f3b8e15ced8a66ad4226" STYLE="vertical-align: middle;" ALT="$$f(t) = t^2 + {t^3\over 2} + {t^4\over 3} + \cdots = - t \cdot ln(1-t)$$" HEIGHT="47" WIDTH="366"&gt;&lt;/center&gt;&lt;br&gt;

therefore&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=0dbc086a7c888a1d0b7659f5710d385e" style="vertical-align: middle;" alt="$$g(t) = - \int t \cdot ln(1-t) dt = \cdots = {1\over 4} (1 - t)^2 - {1\over 2} (1 - t)^2 ln(1 - t) + (1 - t) ln(1 - t) + t + C$$" height="47" width="814" /&gt;&lt;/center&gt;&lt;br&gt;

where the integral is standard. Now,&lt;br&gt;&lt;br&gt;

&lt;center&gt;&lt;img src="http://snappy.at.org/%7Ecola/tex2img/image.php?id=659b1184e90d24dd18dc7a78e334c329" style="vertical-align: middle;" alt="$$g(1) - g(0) = 1 - {1\over 4} = {3\over 4}$$" height="42" width="219" /&gt;&lt;/center&gt;&lt;br&gt;

&lt;span style="font-style: italic;"&gt;Voilà&lt;/span&gt;!&lt;br&gt;&lt;br&gt;

And just to check that things are not too far askew, a sub-exercise in a &lt;a href="http://en.wikipedia.org/wiki/Tacit_programming"&gt;pointless programming&lt;/a&gt;:&lt;br&gt;
&lt;pre&gt;
&lt;b&gt;scala&gt;&lt;/b&gt; (1 to 10000).map(x =&gt; 1.0/(x*(x+2))).reduceLeft(_+_)
&lt;b&gt;res0: Double = 0.749900014997506&lt;/b&gt;
&lt;/pre&gt;&lt;br&gt;&lt;br&gt;

PS: of course this post is an exercise in &lt;a href="http://spiny.at.org/%7Ecola/tex2img"&gt;tex2img&lt;/a&gt; usage.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4955873462769947276?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4955873462769947276/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4955873462769947276' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4955873462769947276'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4955873462769947276'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/08/trivial-exercise.html' title='a trivial exercise.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1995448071384193322</id><published>2009-04-23T09:23:00.006Z</published><updated>2009-06-05T10:57:13.803Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>A Modest Proposal: For Generalizing the Field Access in C Programming Language, and for Making It Beneficial to the Public.</title><content type='html'>&lt;div style="text-align: justify;"&gt;[This is an old and never finished draft. HTML produced by &lt;a href="http://www.methods.co.nz/asciidoc/"&gt;asciidoc&lt;/a&gt;.]

   &lt;/div&gt;&lt;h1&gt;A Modest Proposal: For Generalizing the Field Access in C Programming Language, and for Making It Beneficial to the Public.&lt;/h1&gt;&lt;div style="text-align: justify;"&gt;
   2009.04.22
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Nikita Danilov &amp;lt;danilov@gmail.com&amp;gt;
     v0.1, September 2007&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Abstract&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;A proposal is made to modify C language to make
     accessing &lt;tt&gt;struct&lt;/tt&gt; and &lt;tt&gt;union&lt;/tt&gt; fields
     (&lt;tt&gt;s.f&lt;/tt&gt; and &lt;tt&gt;p-&amp;gt;f&lt;/tt&gt;) more flexible. To that end,
     instead of considering &lt;tt&gt;.f&lt;/tt&gt; and &lt;tt&gt;-&amp;gt;f&lt;/tt&gt; as
     families of unary postfix operators applicable to the values
     of &lt;tt&gt;struct&lt;/tt&gt; and &lt;tt&gt;union&lt;/tt&gt; types and pointers,
     respectively, fields are treated as values or special &lt;em&gt;member
     designator types&lt;/em&gt; introduced for this purpose,
     while &lt;tt&gt;.&lt;/tt&gt; and &lt;tt&gt;-&amp;gt;&lt;/tt&gt; become binary
     operators. Typing rules for the field types and examples of
     their usage are proposed.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;References in square brackets are to the ISO/IEC C standard.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Overview&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;One of the important advantages of C language is the (relative)
     simplicity and cleanness of its memory model: data structures
     eventually boil down to the “objects” [3.15],
     addressable by pointers and contiguous in address space. This is
     most evident in the case of array subscription [6.5.2.1], that
     is &lt;em&gt;defined&lt;/em&gt; through the pointer arithmetic:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;[6.5.2.1] International Standard ISO/IEC 9899&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       Semantics

 [#2] A postfix expression followed by an expression in square
 brackets [] is a subscripted designation of an element of an
 array object.  The definition of the subscript operator [] is
 that E1[E2] is identical to (*((E1)+(E2))).  Because of the
 conversion rules that apply to the binary + operator, if E1 is
 an array object (equivalently, a pointer to the initial element
 of an array object) and E2 is an integer, E1[E2] designates the
 E2-th element of E1 (counting from zero).
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Not only array subscription thus defined makes arrays and pointers
     mostly equivalent, but it also inherits all the good properties of
     addition (commutativity, associativity), and automatically defines the
     meaning of multidimensional arrays.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Another fundamental operation, structure and union member
     de-reference [6.5.2.3] is not, however, similarly reduced to the
     pointer manipulations. Instead, the “Types” [6.2.5]
     section defines types of a sequential (structure) and overlapping
     (union) sets of member objects, and operations are later described
     abstractly as accessing member objects:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;[6.5.2.3] International Standard ISO/IEC 9899&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
 Semantics
 
 [#3] A postfix expression followed by the . operator and  an
 identifier  designates  a  member  of  a  structure or union
 object.  The value is that of the named member,  and  is  an
 lvalue  if  the first expression is an lvalue.
     &lt;/pre&gt;
 &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;The inflexibility of this definition is clear when compared
     with what one can do with the arrays: C permits nothing similar
     to &lt;tt&gt;foo(a0,a1)[bar(b0.b1)]&lt;/tt&gt; for structure and union
     member access. Standard &lt;tt&gt;offsetof()&lt;/tt&gt; macro [7.17]
     converts member designator to an integer constant, equal to the
     member byte offset within the structure of union, but no support
     at the syntax level exists.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;We propose to introduce a family of scalar types representing
     member designators and to define &lt;tt&gt;.&lt;/tt&gt; and &lt;tt&gt;-&amp;gt;&lt;/tt&gt;
     operations in terms of values of these types, in fact, in the
     way very similar to how array subscription is defined.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;The perceived advantages of this are:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;ul style="text-align: justify;"&gt;
     &lt;li&gt;
   array and structure operations become similar;
     &lt;/li&gt;
     &lt;li&gt;
 structure and union operations are reduced to (already defined)
 pointer manipulations, improving orthogonality of the language;
     &lt;/li&gt;
     &lt;li&gt;
 more generic structure-like data types are introduced for free, see
 below.
     &lt;/li&gt;
   &lt;/ul&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Note that in some sense this is not a new development. Vintage C code
     fragments sport usage like&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;v6root/usr/sys/ken/iget.c&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
 iupdat(p, tm)
  int *p;
  int *tm;
  {
         register *ip1, *ip2, *rp;
        int *bp, i;

        rp = p;
        if((rp-&amp;gt;i_flag&amp;amp;(IUPD|IACC)) != 0) {
         ...
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;indicating that member designators (&lt;tt&gt;i_flag&lt;/tt&gt; in this
     case, look at the &lt;em&gt;interesting&lt;/em&gt; declaration of &lt;tt&gt;rp&lt;/tt&gt;) weren't originally tied to a specific structure or union
     type. They were, in fact, existing by themselves in a special
     global namespace—a property that led to the custom of
     prefixing field names with a unique prefix.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Informal proposal&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;A new derived type constructor &lt;tt&gt;-&amp;gt;&lt;/tt&gt; is introduced. A
   declarator&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       TYPE0 -&amp;gt; TYPE1
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;specifies a type of a member designator for a member object with a
     type &lt;tt&gt;TYPE1&lt;/tt&gt; in a type &lt;tt&gt;TYPE0&lt;/tt&gt;.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;A declarator&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       TYPE0 -&amp;gt; TYPE1 :N:M
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;where N and M are integer constants, specifies a type of a
     member designator for a bit-field of a member object starting at
     Nth bit and containing M bits.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Values of any member designator type can be cast to int and
     back without loss of information, passed to and returned from
     the functions, etc. A declaration of the form&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       STRUCT-OR-UNION IDENTIFIER {
               TYPE0 FIELD0;
               TYPE1 FIELD1;
               ...
       };
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;implicitly defines constants of the corresponding member designator
     types for all members of STRUCT-OR-UNION IDENTIFIER type. Defined
     constants have values designating their eponymous structure of union
     members. For example,&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
 struct F {
               int              F_x;
               float            F_y[10];
               void          *(*F_f)(int, struct F *);
               unsigned char    F_b:1;
 };
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;implicitly defines&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       const struct F -&amp;gt; int                        F_x;
       const struct F -&amp;gt; float[10]                  F_y;
       const struct F -&amp;gt; void *(*)(int, struct F *) F_f;
       const struct F -&amp;gt; unsigned char :X:1         F_b; /* for some X */
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;For any non bit-field member FIELD it holds that&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
       offsetof(STRUCT-OR-UNION IDENTIFIER, FIELD) == (int)FIELD
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Following operations are defined on values of member designator
   types:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;ul style="text-align: justify;"&gt;
     &lt;li&gt;
 &lt;p&gt;
   given an expression &lt;tt&gt;E0&lt;/tt&gt; of type “pointer
   to &lt;tt&gt;T0&lt;/tt&gt;”, and an expression &lt;tt&gt;E1&lt;/tt&gt; of
   type &lt;tt&gt;T0 -&amp;gt; T1&lt;/tt&gt;, &lt;tt&gt;E0-&amp;gt;E1&lt;/tt&gt; is equivalent to
 &lt;/p&gt;
 &lt;div class="code"&gt;
   &lt;pre&gt;
           *(T1 *)(((char *)E0) + E1)
   &lt;/pre&gt;
 &lt;/div&gt;
 &lt;p&gt;where &lt;tt&gt;E1&lt;/tt&gt; is implicitly converted to an integer type;&lt;/p&gt;
     &lt;/li&gt;
     &lt;li&gt;
 &lt;p&gt;
   given an expression &lt;tt&gt;E0&lt;/tt&gt; of type &lt;tt&gt;A -&amp;gt; B&lt;/tt&gt;
   and an expression E1 of type &lt;tt&gt;B -&amp;gt; C&lt;/tt&gt;,
   expression &lt;tt&gt;E0.E1&lt;/tt&gt; has type &lt;tt&gt;A -&amp;gt; C&lt;/tt&gt;, and
   corresponds to the member of B, viewed as a member of A;
 &lt;/p&gt;
     &lt;/li&gt;
     &lt;li&gt;
 &lt;p&gt;
   given an expression &lt;tt&gt;E&lt;/tt&gt; of type &lt;tt&gt;A -&amp;gt; B&lt;/tt&gt;, a
   unary expression &lt;tt&gt;-E&lt;/tt&gt; has type &lt;tt&gt;B -&amp;gt; A&lt;/tt&gt;,
   and designates an instance of &lt;tt&gt;A&lt;/tt&gt; in which an
   instance of &lt;tt&gt;B&lt;/tt&gt; designated by &lt;tt&gt;E&lt;/tt&gt; is embedded;
 &lt;/p&gt;
     &lt;/li&gt;
     &lt;li&gt;
 &lt;p&gt;
   a compound assignment &lt;tt&gt;E0 -&amp;gt;= E1&lt;/tt&gt; is defined as an
   abbreviation for &lt;tt&gt;E0 = E0-&amp;gt;E1&lt;/tt&gt;, with E0 evaluated
   only once.
 &lt;/p&gt;
     &lt;/li&gt;
   &lt;/ul&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Examples&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;Example: Basic usage&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
struct F {
       int F_x;
};

struct G {
       int      G_y;
       struct F G_f;
};

void foo() {
       struct G  g;
       struct F *nested;

       printf("designators: %i %i %i\n", F_x, G_y, G_f);
       g.G_y = 1;     /* defined as *(g + G_y) = 1; */
       g.G_f.F_x = 2; /* defined as *(g + G_f.F_x) = 2; */
       nested = &amp;amp;g.G_f;
       /* nested-&amp;gt;(-G_f) is g */
       assert(nested-&amp;gt;(-G_f).G_y == 1);
       /* or... */
       assert(nested-&amp;gt;(-G_f.G_y) == 1);
}
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code-title"&gt;Example: Searching for an item in a linked
   list&lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;&lt;tt&gt;
struct list_link {
       struct list_link *ll_next;
}

struct list_item {
       struct list_link li_next;
       int               li_value;
};

struct list_link *search(struct list_link *s, int key) {
       for (; s &amp;amp;&amp;amp; s-&amp;gt;-li_next.li_value != key; s -&amp;gt;= li_next) {
              ;
       }
       return s;
}
     &lt;/tt&gt;&lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Note that foo-&amp;gt;-bar subsumes container_of() macro (as used in the
     Linux kernel).&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;C is traditionally used as a language for the system
     programming—a domain where one has often to deal with
     formatted data on the storage or network. As a typical example
     let's imagine a system that keeps formatted meta-data, e.g., a
     list of directory entries for a file system or index entries for
     a data-base in a block device block. Different devices have
     different block sizes, which means that in general case format
     of a device block cannot be described by a C structure
     type. With member designator types, however, something similar
     to the following can be done:&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;" class="code"&gt;
     &lt;pre&gt;
/* variable sized device block */
typedef char * block_contents_t;

struct block_format {
       /* magic number at the beginning of the block */
       block_contents_t -&amp;gt; uint32_t bf_start_magic;
       /* array of keys in the index block, growing to the right */
       block_contents_t -&amp;gt; key_t[]  bf_keys;
       /* array of values, corresponding to the keys, growing to the left */
       block_contents_t -&amp;gt; val_t[]  bf_values;
       /* magic number at the end of the block */
       block_contents_t -&amp;gt; uint32_t bf_end_magic;
};

struct system_descriptor {
      ...
      struct block_format sd_format;
      ...
};

void init(struct system_descriptor *desc, int block_size) {
      switch (block_size) {
             case 512:
                    desc-&amp;gt;sd_format.bf_keys      = ...;
                    desc-&amp;gt;sd_format.bf_values    = ...;
                    desc-&amp;gt;sd_format.bf_end_magic = ...;
                    break;
             case 1024:
                    ...
      }
}

int block_search(struct system_descriptor *desc, block_contents_t block,
                key_t *key) {
       int i;

       assert(block-&amp;gt;(desc-&amp;gt;bf_start_magic) == START_MAGIC);
       assert(block-&amp;gt;(desc-&amp;gt;sd_format.bf_end_magic) == END_MAGIC);

       for (i = 0; i &amp;lt; NUM_KEYS; ++i) {
               if (key_cmp(&amp;amp;(block-&amp;gt;(desc-&amp;gt;sd_format.bf_keys))[i], key) {
                       ...
}
     &lt;/pre&gt;
   &lt;/div&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Clearly, quite generic yet type-safe data structures can be
   built this way.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;h2 style="text-align: justify;"&gt;Problems&lt;/h2&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Backward compatibility is broken because field names must be
     unique within a compilation unit now (as they have constants
     declared for them). This is “safe” violation of
     compatibility in that it doesn't change the semantics of an
     existing code silently.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
   &lt;/div&gt;&lt;p style="text-align: justify;"&gt;Meaning of &lt;tt&gt;E0.E1&lt;/tt&gt; for a non-lvalue E0 is awkward to
     define.&lt;/p&gt;&lt;div style="text-align: justify;"&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1995448071384193322?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1995448071384193322/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1995448071384193322' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1995448071384193322'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1995448071384193322'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/04/modest-proposal-for-generalizing-field.html' title='A Modest Proposal: For Generalizing the Field Access in C Programming Language, and for Making It Beneficial to the Public.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-636750832348992096</id><published>2009-03-25T14:20:00.005Z</published><updated>2009-03-25T14:37:54.129Z</updated><title type='text'>It _could_ be done</title><content type='html'>&lt;div align="justify"&gt;
&lt;blockquote&gt;&lt;a href="http://www.multicians.org/andre.html"&gt;The late André Bensoussan worked with me on the Multics [...]. We were working on a major change to the file system [...].&lt;br&gt;
&lt;br&gt;
André took on the job of design, implementation, and test of the VTOC manager. He started by sitting at his desk and drawing a lot of diagrams. I was the project coordinator, so I used to drop in on him and ask how things were going. "Still designing," he'd say. He wanted the diagrams to look beautiful and symmetrical as well as capturing all the state information. [...] I was glad when he finally began writing code. He wrote in pencil, at his desk, instead of using a terminal. [...]&lt;br&gt;
&lt;br&gt;
Finally André took his neat final pencil copy to a terminal and typed the whole program in. His first compilation attempt failed; he corrected three typos, tried again, and the code compiled. We bound it into the system and tried it out, and it worked the first time.&lt;br&gt;
&lt;br&gt;
In fact, the VTOC manager worked perfectly from then on. [...]&lt;br&gt;
&lt;br&gt;
How did André do this, with no tool but a pencil?&lt;/a&gt;&lt;/blockquote&gt;
&lt;br&gt;
Those people were programming operating system kernel that supported kernel level multi-threading and SMP (in 60s!), had most features UNIX kernels have now and some that no later operating system has, like transparent HSM. All under hardware constraints that would make modern washing machine to look like a super-computer. Of course they were thinking, &lt;span style="font-style:italic;"&gt;then&lt;/span&gt; typing.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-636750832348992096?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/636750832348992096/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=636750832348992096' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/636750832348992096'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/636750832348992096'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2009/03/it-could-be-done.html' title='It _could_ be done'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-4443857992164915740</id><published>2007-08-08T22:53:00.000Z</published><updated>2007-08-08T23:47:26.227Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Leisure pace of progress</title><content type='html'>Recently I found a paper in &lt;a href="http://acm.org"&gt;ACM Library&lt;/a&gt; describing two distributed file  systems with the following features:
&lt;ul&gt;
    &lt;li&gt;distributed read-write locking at the byte granularity;&lt;/li&gt;
    &lt;li&gt;user visible distributed transactions with isolation and roll-back;&lt;/li&gt;
    &lt;li&gt;capability based authentication;&lt;/li&gt;
    &lt;li&gt;files implemented as B-trees;&lt;/li&gt;
    &lt;li&gt;distributed garbage collection of unreferenced objects;&lt;/li&gt;
    &lt;li&gt;atomicity through COW (aka &lt;i&gt;shadow writes&lt;/i&gt;, aka &lt;i&gt;wandering logs&lt;/i&gt;);&lt;/li&gt;
    &lt;li&gt;intent logging of file system updates (hello, &lt;a href="http://en.wikipedia.org/wiki/Zfs"&gt;ZFS&lt;/a&gt;);&lt;/li&gt;
    &lt;li&gt;storage failure resilience methods, similar to ones in &lt;a href="http://marc.info/?l=linux-fsdevel&amp;m=117779868908188&amp;w=2"&gt;TileFS&lt;/a&gt;;&lt;/li&gt;
    &lt;li&gt;directories implemented as separate service, using the same interface as usual clients.&lt;/li&gt;
&lt;/ul&gt;
Quite impressive and obviously matched by nothing publicly available currently. How it happened that these marvels are not trumpeted about on every corner? Very simple: these systems were put in production &lt;em&gt;before 1981&lt;/em&gt;. AD, that is. Funny enough, one of them is even named &lt;a href="http://clusterfs.com"&gt;CFS&lt;/a&gt;.
&lt;hr&gt;
[0] James G. Mitchell, Jeremy Dion &lt;i&gt;&lt;a href="http://portal.acm.org/citation.cfm?id=358475&amp;dl=ACM&amp;coll=portal"&gt;A comparison of two network-based file servers&lt;/a&gt;&lt;/i&gt;&lt;br&gt;
[1] Jeremy Dion &lt;i&gt;&lt;a href="http://portal.acm.org/citation.cfm?id=850710&amp;dl=ACM&amp;coll=portal"&gt;The Cambridge File Server&lt;/a&gt;&lt;/i&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-4443857992164915740?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/4443857992164915740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=4443857992164915740' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4443857992164915740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/4443857992164915740'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2007/08/leisure-pace-of-progress.html' title='Leisure pace of progress'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1980494935123400459</id><published>2007-07-18T19:47:00.000Z</published><updated>2007-07-20T12:52:48.511Z</updated><title type='text'>Denver Zoo</title><content type='html'>How to keep a couple of linux kernel developers busy for a day:
&lt;center&gt;&lt;object width="425" height="350"&gt;&lt;param name="movie" value="http://www.youtube.com/v/st-Eloopvi4"&gt;&lt;/param&gt;&lt;param name="wmode" value="transparent"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/st-Eloopvi4" type="application/x-shockwave-flash" wmode="transparent" width="425" height="350"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/center&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1980494935123400459?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1980494935123400459/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1980494935123400459' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1980494935123400459'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1980494935123400459'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2007/07/denver-zoo.html' title='Denver Zoo'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-5448246024063252445</id><published>2007-06-27T21:20:00.001Z</published><updated>2007-06-27T21:39:29.347Z</updated><title type='text'>And now to the subject of death.</title><content type='html'>As little as I want to go into this, some misunderstanding is to be cleared.

Recent &lt;a href="http://www.wired.com/techbiz/people/magazine/15-07/ff_hansreiser?currentPage=1"&gt;interview&lt;/a&gt; [&lt;a href="http://developers.slashdot.org/article.pl?sid=07/06/27/129237&amp;from=rss"&gt;/.&lt;/a&gt;] with jailed Hans Reiser, by Joshua Davis, concludes with the following, presumably ominous paragraph:
&lt;blockquote&gt;While he launches into the intricacies of database science, I'm thinking, "Where is the front passenger seat of your car?" He has never explained this. It seems a fundamental hole in his defense. But he won't stop talking. When I try to interrupt, he insists I let him finish. It's as if the file system holds all the answers.

So I take the hint, and that night, in my office, I start scouring the 80,496 lines of the Reiser4 source code. Eventually I stumble across a passage that starts at line 78,077. It's not part of the program itself &amp;mdash; it's an annotation, a piece of non-executable text in plain English. It's there for the benefit of someone who has chosen to read this far into the code. The passage explains how memory structures are born, grow, and eventually die. It concludes: "Death is a complex process."&lt;/blockquote&gt;

The phrase in question is a part of a large top-of-the-file comment in znode.c, describing, indeed, among other things, a life-cycle of znode (Zam's node) data-structure.

But

&lt;ul&gt;
&lt;li&gt;It is not quoted verbatim (for a better effect, as one is left to assume). Grammatically incorrect original reads:
&lt;div class="code-title"&gt;znode.c&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
   ...
   5. His death.

   Death is complex process.

   When we irrevocably commit ourselves to decision to remove node from the
   tree, JNODE_HEARD_BANSHEE bit is set in zjnode.state of corresponding
   znode. This is done either in -&gt;kill_hook() of internal item or in
   kill_root() function when tree root is removed.
   ...
&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;and, it was &lt;em&gt;me&lt;/em&gt; rather than Hans who wrote this. It was long, long time ago, but I believe SCM logs are still here to prove this.&lt;/li&gt;
&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-5448246024063252445?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/5448246024063252445/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=5448246024063252445' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5448246024063252445'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/5448246024063252445'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2007/06/and-now-to-subject-of-death.html' title='And now to the subject of death.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-6358462845663808948</id><published>2006-10-30T19:00:00.000Z</published><updated>2006-10-30T19:09:44.954Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>File system replacement algorithms (cont.)</title><content type='html'>&lt;div style="text-align: justify;"&gt;
&lt;a href="http://nikitadanilov.blogspot.com/2006/10/file-system-replacement-algorithms.html"&gt;Previous item&lt;/a&gt;.

&lt;h3&gt;3. User level tools.&lt;/h3&gt;
&lt;p&gt;
Replacement algorithms simulator is in &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/replacement.c"&gt;replacement.c&lt;/a&gt;&lt;/tt&gt;. It consists of conventional main loop that reads preprocessed trace records and feeds them to selected replacement algorithm. Replacement algorithms (&lt;tt&gt;struct repalg&lt;/tt&gt;) are executed in the following standard environment:
&lt;ul&gt;
&lt;li&gt;Primary storage (memory) which is an array (&lt;tt&gt;mm.m_frames[]&lt;/tt&gt;) of a given (through command line option) number of equal sized &lt;em&gt;frames&lt;/em&gt; (&lt;tt&gt;struct frame&lt;/tt&gt;). Some frames are &lt;em&gt;occupied&lt;/em&gt; by pages, others are free. Replacement algorithm may maintain some private information for each frame.&lt;/li&gt;
&lt;li&gt;Secondary storage which is an array &lt;tt&gt;mm.m_vpages[]&lt;/tt&gt; of a given number of pages (&lt;tt&gt;struct vpage&lt;/tt&gt;). This can be thought as a set of all distinct pages ever accessed by a trace being processed. Each page, in addition to its index in this array, is uniquely identified by a file and logical offset within this file. At any given moment in time page is either &lt;em&gt;resident&lt;/em&gt; (i.e., loaded into some frame in memory) or non-resident. Replacement algorithm may maintain some private information for each page.&lt;/li&gt;
&lt;li&gt;Array (&lt;tt&gt;mm.m_objects[]&lt;/tt&gt;) of files (&lt;tt&gt;struct object&lt;/tt&gt;). Each file maintains a list of all its pages (not frames!). This is needed for efficient emulation of truncate, see below.&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;p&gt;
These data structures simplify implementation of replacement algorithms, but do not directly match information available in the trace. This gap is filled by preprocessing script &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.awk"&gt;fslog.awk&lt;/a&gt;&lt;/tt&gt; that reads in whole trace and generates unique numeric identifiers for pages and files (these identifiers are used as array indices by replacement emulator). Script also does some additional book-keeping, collects few statistical counters, and does rudimentary sanity checking of the trace. Key point is to reliably tell when pages belong to the same or to the different files. Obvious solution of using &lt;tt&gt;(dev, ino)&lt;/tt&gt; pair as a unique file identifier doesn't work, because certain popular file systems tend to reuse inode numbers immediately after file deletion, leading to false positives. This is why trace record contains additional &lt;tt&gt;-&gt;fr_gen&lt;/tt&gt; and &lt;tt&gt;-&gt;fr_name&lt;/tt&gt; fields: tuple &lt;tt&gt;(dev, ino, generation, name)&lt;/tt&gt; is reliable file identity.
&lt;/p&gt;&lt;p&gt;
Another complication arises with truncate handling. In all other cases trace records produced by kernel map one to one into page accesses, handled by replacement algorithm. But in the case of truncate, kernel walks a list of &lt;em&gt;resident&lt;/em&gt; pages only. Producing trace records for each walked page isn't what we want, because this list depends on a replacement policy implemented by kernel. Instead, tracing patch generates only one record for whole truncate operation, with &lt;tt&gt;-&gt;fr_index&lt;/tt&gt; field indicating the first page to be truncated. For such record &lt;tt&gt;replacement.c&lt;/tt&gt; walks a list of all pages, associated with corresponding file and calls page based truncate entry point (&lt;tt&gt;repalg.m_punch()&lt;/tt&gt;) of replacement algorithm. It is to implement this walking efficiently that files exist as a first class entities in &lt;tt&gt;replacement.c&lt;/tt&gt;.
&lt;/p&gt;&lt;p&gt;
The only remaining bit is converting binary trace records into form suitable for &lt;tt&gt;fslog.awk&lt;/tt&gt;. This is done by &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.c"&gt;fslog.c&lt;/a&gt;&lt;/tt&gt; based on &lt;tt&gt;exported-global.c&lt;/tt&gt; sample program from relayfs package.
&lt;/p&gt;
&lt;h3&gt;4. Results.&lt;/h3&gt;
&lt;h4&gt;4.0. Experiment description.&lt;/h4&gt;
&lt;p&gt;
Analyzed trace was obtained by running
&lt;pre&gt;
$ make defconfig &amp;&amp; make -j4 bzImage modules
&lt;/pre&gt;
&lt;/p&gt;&lt;p&gt;
on a single processor machine (other machine characteristics such as memory size and available secondary storage do not matter, as was explained above) in 2.6.18-rc2 kernel source directory. In addition trace contains records generated during system boot-up. To avoid cluttering the trace with records generated by &lt;tt&gt;fslog.c&lt;/tt&gt; writes, its output was transferred to other machine by netcat(1). Total amount of output was 2.7GB (not provided due to size).
&lt;/p&gt;&lt;p&gt;
&lt;tt&gt;fslog.awk&lt;/tt&gt; &lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.stat"&gt;processed&lt;/a&gt; 25927993 records, accessing total of 2356222 pages in 86839 distinct files. Resulting trace, suitable as input to &lt;tt&gt;replacement.c&lt;/tt&gt; is &lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.trace.gz"&gt;here&lt;/a&gt; (79MB), file identities are &lt;a href="http://linuxhacker.ru/~nikita/fslog/fslog.file"&gt;here&lt;/a&gt;.
&lt;/p&gt;&lt;p&gt;
Following replacement algorithms were tested:
&lt;ul&gt;
&lt;li&gt;RANDOM
&lt;/li&gt;&lt;li&gt;LRU (least recently used)
&lt;/li&gt;&lt;li&gt;FIFO (first in, first out)
&lt;/li&gt;&lt;li&gt;FIFO2 (fifo, second chance)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://portal.acm.org/ft_gateway.cfm?id=805473&amp;type=pdf&amp;coll=portal&amp;dl=ACM&amp;CFID=15151515&amp;CFTOKEN=6184618"&gt;SFIFO&lt;/a&gt; (segmented fifo, by Rollins Turner and Henry Levy)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://www.vldb.org/conf/1994/P439.PDF"&gt;2Q&lt;/a&gt; (by Theodore Johnson and Dennis Shasha)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://citeseer.ist.psu.edu/bansal04car.html"&gt;CAR&lt;/a&gt; (by Sorav Bansal and Dharmendra S. Modha)
&lt;/li&gt;&lt;li&gt;&lt;a href="http://citeseer.ist.psu.edu/megiddo03arc.html"&gt;ARC&lt;/a&gt; (by Nimrod Megiddo, Dharmendra Modha)
&lt;/li&gt;&lt;li&gt;LINUX (emulation of &lt;tt&gt;mm/vmscan.c&lt;/tt&gt;)
&lt;/li&gt;&lt;li&gt;WORST (theoretically worst possible replacement)
&lt;/li&gt;&lt;li&gt;OPT (theoretically optimal clairvoyant algorithm by Belady)&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;&lt;p&gt;
RANDOM, FIFO, FIFO2, LRU and Segmented FIFO are &amp;#8222;classical&amp;#8220; replacement algorithms invented and extensively studied in 60s. 2Q, CAR and ARC are &amp;#8222;new&amp;#8220; algorithms developed recently as interest to replacement policies reappeared. OPT and WORST algorithms cannot be implemented in practice, because they are both &amp;#8222;clairvoyant&amp;#8220; &amp;mdash; they look ahead through the trace. LINUX algorithm tries to emulate &lt;tt&gt;mm/vmscan.c&lt;/tt&gt; with the following limitations and simplifications:
&lt;ul&gt;
&lt;li&gt;no mapped or anonymous pages;
&lt;/li&gt;&lt;li&gt;no kswapd, only direct reclaim;
&lt;/li&gt;&lt;li&gt;all allocations are with GFP_FS;
&lt;/li&gt;&lt;li&gt;no non-fs caches;
&lt;/li&gt;&lt;li&gt;no low_page reserves;
&lt;/li&gt;&lt;li&gt;single zone.&lt;/li&gt;
&lt;/ul&gt;
which is reasonable for comparison of file system dominated non-degenerate work-loads.
&lt;/p&gt;&lt;p&gt;
2Q and SFIFO have tunable parameters (see their papers referenced above for description of parameters). 2Q was tested with &lt;i&gt;kin&lt;/i&gt; of 25, and &lt;i&gt;kout&lt;/i&gt; ranging from 10 to 50 with step 10. &lt;i&gt;kout&lt;/i&gt; of 10 proved to produce best results, and this value was used in comparison with other algorithms. SFIFO was tested &amp;#8222;tail lru percentage&amp;#8220; from 0 (pure FIFO) to 20, with very small observed effect on results. All other algorithms are self-tuning.
&lt;/p&gt;&lt;p&gt;
All algorithms were ran against the same trace, and tested with the same set of memory sizes (varying from 5 to 4M frames, which corresponds to 20KB&amp;mdash;16GB range of memory sizes with 4K frame).
&lt;/p&gt;&lt;p&gt;
Results, together with shell commands used to produce them are available &lt;a href="http://linuxhacker.ru/~nikita/fslog/results"&gt;here&lt;/a&gt;. A couple of notes:
&lt;ul&gt;
&lt;li&gt;OPT algorithm is extremely slow (as expected);
&lt;/li&gt;&lt;li&gt;LINUX algorithm fails for very small memories (less than 64 frames).&lt;/li&gt;
&lt;/ul&gt;
&lt;/p&gt;
&lt;h4&gt;4.1. Graphs: overall.&lt;/h4&gt;
&lt;p&gt;
Below are few graphs, created by gnuplot &lt;a href="http://linuxhacker.ru/~nikita/fslog/plot.gnuplot"&gt;script&lt;/a&gt; (input files for gnuplot are generated by &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/process.hits"&gt;process.hits&lt;/a&gt;&lt;/tt&gt;, and PNG images are generated from postscript by &lt;tt&gt;&lt;a href="http://linuxhacker.ru/~nikita/fslog/generate-png"&gt;generate-png&lt;/a&gt;&lt;/tt&gt;). Everywhere X-axis (horizontal) is memory size (logarithmical), and Y-axis (vertical) is hit ratio in percents, unless specified otherwise.
&lt;/p&gt;&lt;p&gt;
&lt;a name="4.1.overall"&gt;&lt;/a&gt;First, all algorithms on the single graph:
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all.png" border=0&gt;
&lt;/center&gt;
&lt;/p&gt;&lt;p&gt;
One immediate observation is that for memories larger than 28MB difference between algorithms is very small. Another notable thing is that in 56KB&amp;mdash;6MB range LINUX algorithms is worse than everything except WORST. Remarkably it's even worse than RANDOM, which surely is quite a feat of engineering.
&lt;/p&gt;&lt;p&gt;
Next graph shows how algorithms improve upon WORST. Here Y-axis is difference between hit ratio of algorithm and WORST for corresponding memory size.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all-vs-worst.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
As it is by definition impossible to not beat WORST, improvement (or lack thereof) against RANDOM is also useful measure:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all-vs-random.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Next graph shows how far algorithms fall behind OPT. In this graph Y-axis is given by &lt;tt&gt;100.0 - hit_ratio(OPT) + hit_ratio(ALG)&lt;/tt&gt;, that is, OPT corresponds to 100.0.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/all-vs-opt.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Revealed behavior is quite interesting. For very small memory sizes, all algorithms perform more or less equally bad, but as memory size increases, OPT quickly outperforms everything else. This corresponds to the initial dip in the 32KB&amp;mdash;512KB range. After that point, non-OPT algorithms really start &amp;#8222;working&amp;#8220; and gradually approach OPT, reaching (in concert!) local optimum somewhere in 32MB&amp;mdash;64MB range. But as memory size increases even more, &lt;em&gt;all&lt;/em&gt; of them start lagging behind OPT more and more again. In 512MB&amp;mdash;16GB range all algorithms converge, because in this here where total working set of the work load in question lies, and once work set fits into memory it is hard to behave too bad.
&lt;/p&gt;&lt;p&gt;
Second local minimum is rather strange. As it happens for all non-OPT algorithms in a regular manner, it's logical to assume that it is result of some property of the work-load in question. One might hypothesize, that in this range of memory sizes, OPT algorithm is able to exploit some long-term patterns in file system accesses during kernel build.
&lt;/p&gt;&lt;p&gt;
&lt;h4&gt;4.2. Graphs: tunable parameters.&lt;/h4&gt;
&lt;p&gt;
Next, let's look how tunable parameters affect 2Q and SFIFO performance:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/2q-var-lru-opt.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Labels are in &lt;tt&gt;2Q:kin:kout&lt;/tt&gt; format. Obviously, the smaller &lt;i&gt;kout&lt;/i&gt; the better, and 2Q indeed beats LRU most of the time, in accordance with claims of its authors.
&lt;/p&gt;&lt;p&gt;
The same for SFIFO.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/sfifo-var-lru.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Segmented FIFO keeps frames in two lists: head and tail. Head list (containing &amp;#8222;hot&amp;#8220; pages) is maintained in FIFO discipline, and tail list &amp;mdash; in LRU discipline. Size of the tail list is set to fixed percentage of full memory (when this percentage is 0, SFIFO degenerates into FIFO. When it is 100.0, SFIFO becomes LRU.). The logic behind this is that by making tail LRU list sufficiently small it becomes practically feasible to implement LRU in it by un-mapping pages on entry to tail list. Our results show that for all reasonable sizes of tail list, difference in hit ratio is negligible.
&lt;/p&gt;
&lt;h4&gt;4.2. Graphs: classical algorithms.&lt;/h4&gt;
&lt;p&gt;
Let's look at some data of historical interest: how &amp;#8222;classical&amp;#8220; replacement algorithms (LRU, FIFO, and FIFO2) behave relative to OPT, WORST, and RANDOM (LINUX is shown here too, because it basically falls into the same class of algorithms).
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-worst.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
Classical algorithms versus WORST:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-vs-worst.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
And versus OPT:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-vs-opt.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
It's interesting to look how these algorithms behave in the memory ranges typical for the time when they were actively researched:
&lt;/p&gt;&lt;p&gt;
2MB&amp;mdash;32MB range:
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-2M-32M.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
At some points difference in hit ratios can reach 5%, but as we move to larger memories (16MB&amp;mdash;4GB)...
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-16M-4G.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
difference shrinks to ~1% range and remains there (256MB&amp;mdash;4GB):
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/old-opt-256M-4G.png" border=0&gt;
&lt;/center&gt;
&lt;h4&gt;4.3. Graphs: LINUX.&lt;/h4&gt;
&lt;p&gt;
At last, compare how LINUX fares relative to other algorithms. We shall concentrate on data for large memories (64MB&amp;mdash;4GB range), because behavior of LINUX algorithm in low memory setups is clearly visible at the &lt;a href="#4.1.overall"&gt;overall graph&lt;/a&gt;: it loses to everyone.
&lt;/p&gt;
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/lru-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/fifo-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/fifo2-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/arc-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/2q-linux-64M-4G.png" border=0&gt;
&lt;/center&gt;
&lt;p&gt;
The natural question arises: why LINUX algorithm is so... not brilliant (albeit, keep in mind that all this happens only few percent within OPT, so not too much is at the stake)? As was noted at the beginning, unified FS/VM caching forces replacement algorithm to use only bare minimum of available per-page information. In particular, it so happens that for clean file system pages, LINUX is equivalent to FIFO (known bad algorithm), and for dirty pages &amp;mdash; to FIFO2.
&lt;/p&gt;
&lt;!--
&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/modern-lru-opt-16M-4G.png" border=0&gt;
&lt;/center&gt;

&lt;center&gt;
&lt;img src="http://linuxhacker.ru/~nikita/fslog/png/modern-lru-opt.png" border=0&gt;
&lt;/center&gt;
--&gt;
&lt;h3&gt;5. Conclusion.&lt;/h3&gt;
&lt;p&gt;
Assorted miscellaneous notes, actually.
&lt;/p&gt;&lt;p&gt;
One thing obvious from traces, but not mentioned above is that larger portion of all trace records is for page faults. Absolute majority of them are compulsory misses that happen because every new process maps all standard libraries into its address space. By looking at the traces, it seems that optimizations in this area (e.g., pre-mapping all already resident pages of the given library) would be clearly advantageous.
&lt;/p&gt;&lt;p&gt;
Handling of file system pages by LINUX algorithms can definitely be improved.
&lt;/p&gt;
&lt;h3&gt;6. Future directions.&lt;/h3&gt;
&lt;p&gt;
More algorithms are to be implemented in &lt;tt&gt;replacement.c&lt;/tt&gt;: LFU, LRU/k, LIRS, etc. Also, more statistics (working set size, page fault rate, etc.) can be collected.
&lt;/p&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-6358462845663808948?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/6358462845663808948/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=6358462845663808948' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/6358462845663808948'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/6358462845663808948'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/10/previous-item.html' title='File system replacement algorithms (cont.)'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-1326414144463107737</id><published>2006-10-29T22:08:00.000Z</published><updated>2006-10-30T19:13:04.437Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>File system replacement algorithms.</title><content type='html'>&lt;div style="text-align: justify;"&gt;
&lt;h3&gt;1. Introduction.&lt;/h3&gt;This article describes results of a bit of research I made on efficiency of file system cache replacement algorithms. As everybody knows file system tries to keep some portions of its backing secondary storage (disk) cached in the primary storage (memory). In particular portion of file system data or meta-data that is being accessed right now has to be present in the memory, because kernel cannot directly manipulate data on the disk. &lt;em&gt;Replacement problem&lt;/em&gt; occurs when this cache grows too large (which it tends to do sooner or later, as secondary storage is usually much larger than memory). When cache cannot grow anymore, and new data have to be accessed, something has to be thrown out of the cache. The selection of cache item to be removed is made by &lt;em&gt;replacement algorithm&lt;/em&gt;. Choice of this algorithm affects file system performance, because if/when item removed from cache is re-accessed, file system has to wait for disk IO to read it again. Replacement algorithms try to minimize this overhead, by using various statistical information and trying to predict future accesses.

The very possibility of such predictions is based on assumed regularities in file system accesses, most notable being &lt;em&gt;&lt;a href="http://en.wikipedia.org/wiki/Locality_of_reference"&gt;locality of reference&lt;/a&gt;&lt;/em&gt; and access patterns, such as sequential file scanning.

Research in replacement algorithms is as old as file systems, but few last decades in was mainly done in the context of data base engines (that also cache part of database in the memory). The reason for this is that in most modern operating system kernels file system caching was unified with VM caching. Perceived advantages of this unification are:
&lt;ul&gt;&lt;li&gt;simplification,
&lt;/li&gt;&lt;li&gt;support of &lt;a href="http://opengroup.org/onlinepubs/009695399/functions/mmap.html"&gt;mmap(2)&lt;/a&gt; style accesses to file system, and
&lt;/li&gt;&lt;li&gt;sharing of memory between file system and VM, without imposing artificial limits on size of each cache.
&lt;/li&gt;&lt;/ul&gt;The latter goal was never fully achieved: all existing implementations treat file system and VM pages differently to some extent, because system performance is miserable otherwise. This hints that access patterns are so different for file system and VM pages, that unified caching is not necessary the best solution.

Another problem with unified caching is that the same replacement algorithm has to be used, and this basically means that replacement algorithm may rely only on information available for both file system and VM pages to make its decisions. As a set of attributes that file system can maintain for its pages is a strict superset of attributes maintained for VM pages, unified replacement algorithm degenerates into a &lt;a href="http://en.wikipedia.org/wiki/Page_replacement_algorithms"&gt;VM replacement algorithm&lt;/a&gt; and all additional hints that file system can provide are thrown away.

Experiments described below are an attempt to determine whether separate replacement algorithm can improve file system performance.

To measure efficiency of replacement algorithms file system traces were collected, and then processed by a user-level simulator.

Trace is a sequence of records each describing a particular access to some page of a file (see details below). User level simulator processes trace record by record, emulating both memory and secondary storage, keeping track of currently cached pages, and performing replacement decisions when necessary (also, see below for details).
&lt;h3&gt;2. Tracing method.
&lt;/h3&gt;An important point in collecting file system traces is to make them independent from caching and replacement algorithms implemented in the kernel being traced. This, for example, rules out placing tracepoints at the level of &lt;tt&gt;struct address_space_operations&lt;/tt&gt; (or below), because code at that level is invoked by VM, and as a result sequence of event depends on algorithms used by VM.

On the other hand, placing tracepoints at the syscall/VFS level is not very convenient either, because, while usable for tracing access to data pages (read/write/truncate), it is not adequate for tracing meta-data.

The only remaining possibility is to put tracepoints into file system driver, but that would require changing all file systems. As a compromise, tracepoints were placed in &lt;tt&gt;mm/filemap.c&lt;/tt&gt;, &lt;tt&gt;mm/readahead.c&lt;/tt&gt; and &lt;tt&gt;mm/truncate.c&lt;/tt&gt; "generic" code that is used by many file systems:
&lt;dl&gt;&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=do_generic_mapping_read"&gt;do_generic_mapping_read()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts reads&lt;/dd&gt;&lt;dt&gt;
&lt;/dt&gt;&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=filemap_nopage"&gt;filemap_nopage&lt;/a&gt;()&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts page faults on file system pages&lt;/dd&gt;
&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=filemap_nopage"&gt;__grab_cache_page()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts writes&lt;/dd&gt;
&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=truncate_inode_pages_range"&gt;truncate_inode_pages_range()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts truncates&lt;/dd&gt;
&lt;dt&gt;&lt;tt&gt;&lt;a href="http://lxr.linux.no/ident?i=__do_page_cache_readahead"&gt;__do_page_cache_readahead()&lt;/a&gt;&lt;/tt&gt;
&lt;/dt&gt;&lt;dd&gt;intercepts readahead
&lt;/dd&gt;&lt;/dl&gt;All tracepoints look exactly the same:
&lt;div class="code-title"&gt;tracepoint&lt;/div&gt;
&lt;div class="code"&gt;&lt;pre&gt;
 fslog(mapping, index, page, opcode);
&lt;/pre&gt;&lt;/div&gt;

Where &lt;tt&gt;mapping&lt;/tt&gt; is an object (inode) on which operation is preformed, &lt;tt&gt;index&lt;/tt&gt; is a logical offset of accessed page within object, &lt;tt&gt;page&lt;/tt&gt; is a page itself, if present, NULL otherwise, and &lt;tt&gt;opcode&lt;/tt&gt; is operation code, one of

&lt;div class="code-title"&gt;enum fslog_rec_type&lt;/div&gt;
&lt;div class="code"&gt;&lt;pre&gt;
enum fslog_rec_type {
        FSLOG_READ,    /* read */
        FSLOG_RA,      /* read-ahead */
        FSLOG_WRITE,   /* write */
        FSLOG_PFAULT,  /* page-fault */
        FSLOG_PUNCH    /* page truncate */
};
&lt;/pre&gt;&lt;/div&gt;&lt;tt&gt;fslog()&lt;/tt&gt; packs arguments into standard event record:
&lt;div class="code-title"&gt;struct fslog_record
&lt;/div&gt;&lt;div class="code"&gt;&lt;pre&gt;struct fslog_record {
        __u32 fr_no;       /* monotonically increasing event counter.
                              Used to detect lost events. */
        __u32 fr_time;     /* event time in microseconds. */

        __u32 fr_dev;      /* major:minor of device, where file is located. */
        __u32 fr_ino;      /* file inode number */

        __u32 fr_gen;      /* file inode generation. */
        __u32 fr_index;    /* logical index of accessed page. */

        __u16 fr_pid;      /* pid of process. */
        __u8  fr_type;     /* access type, taken from enum fslog_rec_type. */
        __u8  fr_bits;     /* miscellaneous page bits. */
        __u32 fr_pad;      /* alignment padding. */

        char  fr_comm[16]; /* "process name". */
        char  fr_name[16]; /* "file name". */
};
&lt;/pre&gt;&lt;/div&gt;That might looks like awfully excessive amount of information, but it's necessary to reliably identify unique pages and files, as will be shown below.

Once record is composed, it is exported to the user space through &lt;a href="http://relayfs.sourceforge.net/"&gt;relayfs&lt;/a&gt;.

Tracing patch for 2.6.18-rc2 kernel is available &lt;a href="http://linuxhacker.ru/%7Enikita/fslog/fslog.patch"&gt;here&lt;/a&gt;.

&lt;a href="http://nikitadanilov.blogspot.com/2006/10/previous-item.html"&gt;Continued&lt;/a&gt;.
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-1326414144463107737?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/1326414144463107737/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=1326414144463107737' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1326414144463107737'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/1326414144463107737'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/10/file-system-replacement-algorithms.html' title='File system replacement algorithms.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-115359710401539766</id><published>2006-07-22T19:33:00.000Z</published><updated>2006-07-22T19:38:24.026Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>A voice of the reason from the distant past</title><content type='html'>Dedicated to VM and file system developers and researches...
&lt;blockquote&gt;
It is immediately apparent from these figures that moving-arm disks should never be used, neither for paging applications nor for any other heavy-traffic auxiliary memory applications.
&lt;/blockquote&gt;&lt;div style="text-align: right;"&gt;Peter J. Denning -- &lt;a href="http://portal.acm.org/ft_gateway.cfm?id=356573&amp;type=pdf&amp;coll=portal&amp;dl=ACM&amp;CFID=15151515&amp;CFTOKEN=6184618"&gt;Virtual Memory&lt;/a&gt;.
&lt;/div&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/VM" rel="tag"&gt;VM&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-115359710401539766?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/115359710401539766/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=115359710401539766' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/115359710401539766'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/115359710401539766'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/07/voice-of-reason-from-distant-past.html' title='A voice of the reason from the distant past'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-114340358190033239</id><published>2006-03-26T20:01:00.000Z</published><updated>2006-03-26T20:31:55.380Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='reiser4'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>reiser4: 1. internal tree</title><content type='html'>&lt;h1&gt;reiser4: 1. internal tree&lt;/h1&gt;

&lt;p&gt;
     This continues previous entry: &lt;a href="http://nikitadanilov.blogspot.com/2005/12/reiser4-0-introduction.html"&gt;introduction&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;
   &lt;ul&gt;
     &lt;li&gt;0. &lt;a href="#internal-tree-0"&gt;B-trees overview&lt;/a&gt;
     &lt;/li&gt;&lt;li&gt;1. &lt;a href="#internal-tree-1"&gt;lookup and modification&lt;/a&gt;
     &lt;/li&gt;&lt;li&gt;2. &lt;a href="#internal-tree-2"&gt;lookup optimizations&lt;/a&gt;
     &lt;/li&gt;
   &lt;/ul&gt;
&lt;/p&gt;
&lt;h4&gt;0. B-trees overview&lt;/h4&gt;
&lt;div class="kernel"&gt;&lt;a name="internal-tree-0"&gt;&lt;/a&gt;
&lt;p&gt;
    &lt;a href="http://en.wikipedia.org/wiki/B-tree"&gt;B-tree&lt;/a&gt; is am umbrella term for a variety of similar algorithms used to implement &lt;a href="http://en.wikipedia.org/wiki/Associative_array"&gt;dictionary&lt;/a&gt; abstraction suitable in a form suitable for external storage. Reiser4 version of this algorithms, officially known as a &lt;a href="http://en.wikipedia.org/wiki/Dancing_tree"&gt;dancing tree&lt;/a&gt; is closest to the &lt;a href="http://en.wikipedia.org/wiki/B%2B_tree"&gt;B&lt;sup&gt;+&lt;/sup&gt;-tree&lt;/a&gt;. Basically, in B&lt;sup&gt;+&lt;/sup&gt;-tree user-supplied data records are stored in &lt;em&gt;leaf nodes&lt;/em&gt;. Each leaf node keeps records from some particular key range (adjusted dynamically). Each leaf node is referenced from its &lt;em&gt;parent&lt;/em&gt;: this reference is a pointer to the child (block number usually) and the smallest key in the key range covered by this leaf. Parent node contains multiple references to its children nodes, again from some particular key range. Parent node may have its own parent and so on until whole key space is covered.
&lt;/p&gt;&lt;p&gt;
   Compare this with B-trees proper, where data records are stored at the levels other than leaf one. Also compare this with &lt;a href="http://en.wikipedia.org/wiki/PATRICIA"&gt;radix tree&lt;/a&gt; (aka &lt;em&gt;PATRICIA&lt;/em&gt;) where key range covered by given node is uniquely determined by its level rather than adjusted dynamically as in B-trees.
&lt;/p&gt;&lt;p&gt;
  Contents of reiser4 internal tree are initially stored on the disk. As file system operations go on, some blocks from the tree are read into memory and cached there. When new node is added to the tree, it first exists as a block-size buffer in memory. Under some conditions portions of tree are written out from memory back to the stable storage. During write-out, nodes that were marked &lt;em&gt;dirty&lt;/em&gt; (either as a result of a modification, or because they are newly created), are written to the appropriate disk block and marked &lt;em&gt;clean&lt;/em&gt;. Clean nodes can be discarded from memory.
&lt;/p&gt;
&lt;/div&gt;


&lt;h4&gt;1. lookup and modification&lt;/h4&gt;
&lt;div class="kernel"&gt;&lt;a name="internal-tree-1"&gt;&lt;/a&gt;
&lt;p&gt;
   Lookup operation locates a record with a given key in a tree, or locates a place where such record will be inserted (this place is uniquely identified by a key) if it doesn't exist yet. All other tree operations start with lookup, because they have to find a place in a tree identified by given key.
&lt;/p&gt;&lt;p&gt;
   Roughly speaking, lookup starts from the top of the tree, searches through index node to find it which of its children given key falls, loads that child node and repeats until it gets to the leaf level. One can say that lookup is top-to-bottom tree operation.
&lt;/p&gt;
   This poses two questions:
&lt;ul&gt;
  &lt;li&gt;What is the top of a tree and how to find it?&lt;/li&gt;
  &lt;li&gt;How to find out which child node to proceed with?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
  First question seems trivial, because every tree has a root node, right? The problem is that, as will be explained below, concurrent tree modification operation may grow the tree by adding new root to it (so that old root becomes child of a new one), or shrink it by killing existing root. To avoid this, reiser4 tree has special imaginary node, existing only in memory that logically hangs just above root node. First of all, lookup locks this node and learns location of root node from it. After this, it loads root node in memory and releases the lock. This imaginary node is called &lt;a href="http://en.wiktionary.org/wiki/%C3%BCber"&gt;uber&lt;/a&gt;-node. Curiously enough, Sun ZFS uses exactly the same term for the very similar thing. They even have &lt;tt&gt;0x00babl0c&lt;/tt&gt; magic number in their disk format, that is supposed to be as close as possible to the &lt;em&gt;pronunciation&lt;/em&gt; of "uber block" (even more funny, "bablo" is Russian slang word for money, bucks).
&lt;/p&gt;&lt;p&gt;
  To make search for a child node containing given key efficient, keys in the parent node are stored in an ordered array, so that binary search can be used. That binary search is (under many workloads) the single most critical CPU operation.
&lt;/p&gt;
    Now we known enough to code reiser4 lookup algorithm:
&lt;div class="code-title"&gt;reiser4/search.c:traverse_tree()&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
traverse_tree(key) {
        node     *parent; /* parent node */
        node     *child;  /* child node */
        position  ptr;    /* position of record within node */

        child = ubernode;
        ptr   = ubernode.root; /* put root block number in ptr */

        while (!node_is_leaf(child)) {
                parent = child;
                /* load node, stored at the given block, into memory */
                child = node_at(ptr);
                lock(child);
                ptr = binary_search(child, key);
                unlock(parent);
        }
        return ptr;
}
&lt;/pre&gt;
&lt;/div&gt;
Few comments:
&lt;ul&gt;
&lt;li&gt;&lt;tt&gt;position&lt;/tt&gt; identifies a record within node. For leaf level this is actual record with user data, for non-leaf levels, record contains pointers to the child node.
&lt;/li&gt;&lt;li&gt;note that lock on the child node is acquired before lock on the parent is released, that is, two locks are held at some moment. This is traditional tree traversal technique called &lt;em&gt;lock coupling&lt;/em&gt; or &lt;em&gt;lock crabbing&lt;/em&gt;.
&lt;/li&gt;&lt;li&gt;&lt;tt&gt;traverse_tree()&lt;/tt&gt; returns with ptr positioned at the record with required key (or at the place where such record would be inserted) and with appropriate leaf node locked.
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;
   As was already mentioned above, tree lookup is comparatively expensive (computationally, if nothing more) operation. At the same time, almost everything in reiser4 uses it extensively. As a result, significant effort has been put into making tree lookup more efficient. Algorithm itself doesn't leave much to be desired: its core is binary search and it can be optimized only that far. Instead, multiple mechanisms were developed that allows to bypass full tree lookup under some conditions. These mechanisms are:
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#internal-tree-1-1"&gt;seals&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="#internal-tree-1-2"&gt;vroot&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="#internal-tree-1-3"&gt;look-aside cache&lt;/a&gt; (cbk cache)
&lt;/li&gt;
&lt;/ul&gt;
&lt;h5&gt;1.1. seals&lt;/h5&gt;&lt;a name="internal-tree-1-1"&gt;&lt;/a&gt;
&lt;p&gt;
   A seal is a weak pointer to a record in the tree. Every node in a tree maintains &lt;em&gt;version counter&lt;/em&gt;, that is incremented on each node modification. After lookup for a given key was performed, seal can be created that remembers block number of found leaf node and its version counter at the moment of lookup. Seal verification process checks that node recorded in the seal is still in the tree and that its version counter is still the same as recorded. If both conditions are met, pointer to the record returned by lookup can still be used, and additional lookup for the same key can be avoided.
&lt;/p&gt;
&lt;h5&gt;1.2. vroot&lt;/h5&gt;&lt;a name="internal-tree-1-2"&gt;&lt;/a&gt;
&lt;p&gt;
   Higher-level file system object such as regular files and directories is represented as a set of tree records. Keys of these records are usually confined in some key range, and, due to the nature of B-trees, are all stored in the nodes having common ancestor node that is not necessary root. That is, records constituting given object are located in some subtree of reiser4 internal tree. Idea of vroot (&lt;em&gt;virtual root&lt;/em&gt;) optimization is to track root of that sub-tree and to start lookups for object records from vroot rather than from real tree root. vroot is updated lazily: when lookup finds that tree was modified so that object subtree is no longer rooted at vroot, tree traversal restarts from real tree root and vroot is determined during descent.
&lt;/p&gt;&lt;p&gt;
   Additional important advantage of vroot is that is decreases lock contention for the root node.
&lt;/p&gt;
&lt;h5&gt;1.3. look-aside cache&lt;/h5&gt;&lt;a name="internal-tree-1-3"&gt;&lt;/a&gt;
&lt;p&gt;
  Look-aside cache is simply a list of last N leaf nodes returned by tree lookup. This list is consulted before embarking into full-blown top-to-bottom traversal. This simple mechanism works due to &lt;a href="http://en.wikipedia.org/wiki/Locality_of_reference"&gt;locality of reference&lt;/a&gt; for tree accesses.
&lt;/p&gt;
  To be continued:
&lt;ul&gt;
     &lt;/li&gt;&lt;li&gt;2. concurrency control: lock ordering, hi-lo ordering
     &lt;/li&gt;&lt;li&gt;3. eottl
     &lt;/li&gt;&lt;li&gt;4. node format
&lt;/ul&gt;
&lt;/div&gt;


&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/reiser4" rel="tag"&gt;reiser4&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-114340358190033239?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/114340358190033239/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=114340358190033239' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114340358190033239'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114340358190033239'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/03/reiser4-1-internal-tree.html' title='reiser4: 1. internal tree'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-114301477508079978</id><published>2006-03-22T07:59:00.000Z</published><updated>2006-03-22T08:06:35.003Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='mathematics'/><title type='text'>Jon Beck dies</title><content type='html'>&lt;div class="mourning"&gt;
&lt;center&gt;
Jon Beck, author of &lt;i&gt;&lt;a href="http://en.wikipedia.org/wiki/Beck%27s_monadicity_theorem"&gt;Beck's condition&lt;/a&gt;&lt;/i&gt;, died suddenly on March 11.
&lt;/center&gt;
&lt;/div&gt;
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Mathematics" rel="tag"&gt;Mathematics&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------

&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-114301477508079978?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/114301477508079978/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=114301477508079978' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114301477508079978'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114301477508079978'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/03/jon-beck-dies.html' title='Jon Beck dies'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-114141075488944431</id><published>2006-03-03T18:31:00.000Z</published><updated>2006-03-04T15:36:01.300Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>Why windows will collapse ultimately</title><content type='html'>&lt;pre&gt;Subject: [ntdev] WdfUsbTargetDeviceSendControlTransferSynchronously and timeouts&lt;/pre&gt;

&lt;b&gt;update&lt;/b&gt;: Like this wasn't enough.

Below are excerpts from
&lt;pre&gt;
find . -name \*dll |        xargs strings -- |        grep -i '^[a-z0-9_]*$' |        awk '{ print length($1) "\t" $1 }' |        sort -n
&lt;/pre&gt;
output (executed in WinXP system directory):
&lt;pre&gt;
50      ZwAccessCheckByTypeResultListAndAuditAlarmByHandle
51      Java_NPDS_npDSJavaPeer_SetSendMouseClickEvents_stub
51      Java_NPDS_npDSJavaPeer_SetShowPositionControls_stub
51      JET_errDistributedTransactionNotYetPreparedToCommit
52      ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION
52      ConvertSecurityDescriptorToStringSecurityDescriptorA
52      ConvertSecurityDescriptorToStringSecurityDescriptorW
53      ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE
55      ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION
55      SxspComProgIdRedirectionStringSectionGenerationCallback
56      Java_NPDS_npDSJavaPeer_GetSendOpenStateChangeEvents_stub
56      Java_NPDS_npDSJavaPeer_GetSendPlayStateChangeEvents_stub
56      SxspComTypeLibRedirectionStringSectionGenerationCallback
57      SxspComputeInternalAssemblyIdentityAttributeBytesRequired
57      SxspWindowClassRedirectionStringSectionGenerationCallback
62      SxspComputeInternalAssemblyIdentityAttributeEncodedTextualSize
62      SxspGenerateTextuallyEncodedPolicyIdentityFromAssemblyIdentity
64      RtlpQueryAssemblyInformationActivationContextDetailedInformation
71      &lt;a href="http://www.openrce.org/reference_library/win32_call_chains/XPSP2/NTDLL/RtlpQueryFilesInAssemblyInformationActivationContextDetailedInformation"&gt;RtlpQueryFilesInAssemblyInformationActivationContextDetailedInformation&lt;/a&gt;
&lt;/pre&gt;

which probably gives us the champion. 

As a comparison, for linux-2.6.15
&lt;pre&gt;
find . -type f -follow -name '*.[chS]' |        xargs grep -hi '[a-z0-9_]\{70,\}' -- /dev/null
&lt;/pre&gt;
gives:
&lt;pre&gt;
70 ZORRO_PROD_PHASE5_BLIZZARD_1230_II_FASTLANE_Z3_CYBERSCSI_CYBERSTORM060
&lt;/pre&gt;
So windows is one character closer to hell than linux.
&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Programming" rel="tag"&gt;Programming&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Windows" rel="tag"&gt;Windows&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-114141075488944431?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/114141075488944431/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=114141075488944431' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114141075488944431'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/114141075488944431'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/03/why-windows-will-collapse-ultimately.html' title='Why windows will collapse ultimately'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113882577109399193</id><published>2006-02-01T20:02:00.000Z</published><updated>2006-02-01T20:34:44.473Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='file system'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>ext3: magic, more magic.</title><content type='html'>&lt;span class="fullpostellipsis"&gt;
&lt;p&gt;
ext3 htree code in Linux kernel implements peculiar version of &lt;a href="http://www.bluerwhite.org/btree/"&gt;balanced tree&lt;/a&gt; used to efficiently handle large directories.
&lt;/p&gt;&lt;p&gt;
htree directory consists of block sized nodes. Some of them (leaf nodes) contain directory entries in the same format as ext2. Other nodes contain &lt;i&gt;index&lt;/i&gt;: they are filled with hashes and pointers to other nodes.
&lt;/p&gt;&lt;p&gt;
When new file is created in a directory, a directory entry is inserted in one of leaf nodes. When leaf node has not enough space for new entry, new node is appended to the tree, and part of directory entries is moved there. This process is known as a &lt;i&gt;split&lt;/i&gt;. Pointer to new node is then inserted into some index node, and new node can overflow at this point, causing another split and so on.
&lt;/p&gt;&lt;p&gt;
If splits occur whole way up to the root of the tree, new root has to be added (tree grows).
&lt;/p&gt;&lt;p&gt;
It's obvious that in the worst case (extremely rare in practice) insertion of a new entry may require a new block on each tree level, plus new root, right? Now, looking at the &lt;a href="http://lxr.linux.no/ident?i=ext3_dx_add_entry"&gt;&lt;tt&gt;ext3_dx_add_entry()&lt;/tt&gt;&lt;/a&gt; function we see something strange:
&lt;/p&gt;
&lt;div class="code-title"&gt;&lt;a href="http://lxr.linux.no/source/fs/ext3/namei.c#L1515"&gt;fs/ext3/namei.c:ext3_dx_add_entry()&lt;/a&gt;&lt;/div&gt;
&lt;div class="code"&gt;
&lt;pre&gt;
                 } else {
                         dxtrace(printk("Creating second level index...\n"));
                         memcpy((char *) entries2, (char *) entries,
                                icount * sizeof(struct dx_entry));
                         dx_set_limit(entries2, dx_node_limit(dir));
 
                         /* Set up root */
                         dx_set_count(entries, 1);
                         dx_set_block(entries + 0, newblock);
                         ((struct dx_root *) frames[0].bh-&gt;b_data)-&gt;info.indirect_levels = 1;
 
                         /* Add new access path frame */
                         frame = frames + 1;
                         frame-&gt;at = at = at - entries + entries2;
                         frame-&gt;entries = entries = entries2;
                         frame-&gt;bh = bh2;
                         err = ext3_journal_get_write_access(handle,
                                                              frame-&gt;bh);
                         if (err)
                                 goto journal_error;
                 }
&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;
At this moment &lt;tt&gt;entries&lt;/tt&gt; points to the already existing full node and &lt;tt&gt;entries2&lt;/tt&gt; to the newly created one. As one can see, contents of &lt;tt&gt;entries&lt;/tt&gt; is shifted into &lt;tt&gt;entries2&lt;/tt&gt;, and &lt;tt&gt;entries&lt;/tt&gt; is declared to be new root of the tree. So now tree has a root node with a single pointer to the index node that... still has not enough free space (remember &lt;tt&gt;entries2&lt;/tt&gt; got everything &lt;tt&gt;entries&lt;/tt&gt; had). Omitted code that follows proceeds with splitting leaf node, assuming that its parent has enough space to insert a pointer to the new leaf. So how this is supposed to work? Or, does this work at all? That's tricky part and the curious reader is invited to try to infer what's going on without looking at the rest of this post.
&lt;/p&gt;
&lt;b&gt;[&lt;/b&gt;full text follows&lt;b&gt;]&lt;/b&gt;&lt;/span&gt;
&lt;span class="fullpost"&gt;
&lt;p&gt;The answer is simple: by ext3 htree design, capacity of the root node is smaller than that of non-root index one. This is a byproduct of binary compatibility between htree and old ext2 format: root node is always the first block in the directory and it always contains dot and dotdot directory entries. As a result, when contents of old root is copied into new node, that node ends up having enough space for two additional entries.
&lt;/p&gt;&lt;p&gt;
This is obviously one of the worst hacks &lt;b&gt;and&lt;/b&gt; least documented at that. Shame.
&lt;/p&gt;&lt;p&gt;
Thanks to Alex Tomas for clearing this mystery for me. As he says: "&lt;i&gt;Htree code is simple to understand: it only takes to tune yourself to Daniel Phillips brain-waves frequency&lt;/i&gt;".
&lt;/p&gt;
&lt;/span&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Linux" rel="tag"&gt;Linux&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113882577109399193?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113882577109399193/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113882577109399193' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113882577109399193'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113882577109399193'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/02/ext3-magic-more-magic.html' title='ext3: magic, more magic.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113699963009595222</id><published>2006-01-11T16:38:00.000Z</published><updated>2006-01-11T17:14:25.563Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><category scheme='http://www.blogger.com/atom/ns#' term='kernel'/><title type='text'>A bit of out-of-context quoting</title><content type='html'>&lt;blockquote&gt;
&lt;a href="http://blogs.sun.com/roller/resources/esaxe/recruiting-preso-v2.pdf"&gt;Lessons Learned&lt;/a&gt;
&lt;ul&gt;
    &lt;li&gt; Solaris has been functioning, essentially, by accident, for over one year.&lt;br&gt;
         &lt;i&gt;We realize this again and again, every so often...&lt;/i&gt;&lt;/li&gt;
    &lt;li&gt;It is amazing that anything works at all&lt;/li&gt;
    &lt;li&gt;It's all broken&lt;/li&gt;
    &lt;li&gt;...&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Solaris" rel="tag"&gt;Solaris&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Kernel" rel="tag"&gt;Kernel&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113699963009595222?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113699963009595222/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113699963009595222' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113699963009595222'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113699963009595222'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/01/bit-of-out-of-context-quoting.html' title='A bit of out-of-context quoting'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5799246.post-113698564744894743</id><published>2006-01-11T13:17:00.000Z</published><updated>2006-01-11T13:20:47.463Z</updated><title type='text'>A visit to the countryside.</title><content type='html'>&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0047.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0047.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- hidden church --&gt;
&lt;br&gt;
The Hidden Church
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0050.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0050.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- oka --&gt;
&lt;br&gt;
Oka riverside
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0055.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0055.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- a window --&gt;
&lt;br&gt;
An interior of a room of &lt;a href="http://en.wikipedia.org/wiki/Vasily_Polenov"&gt;Polenov's&lt;/a&gt; house.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0054.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0054.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- butterflies --&gt;
&lt;br&gt;
A painting by Polenov.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0044.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0044.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- ice tree --&gt;
&lt;br&gt;
An ice tree.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0058.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0058.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- landscape --&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0063.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0063.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- landscape with a bus --&gt;
&lt;br&gt;
Landscapes.
&lt;br&gt;&lt;br&gt;

&lt;a href="http://linuxhacker.ru/~nikita/images/2006.01/cimg0018.jpg"&gt;&lt;img src="http://linuxhacker.ru/~nikita/images/2006.01/cimg0018.t.jpg" border=0&gt;&lt;/a&gt;
&lt;!-- wisent aurochs --&gt;
&lt;br&gt;
A wisent.
&lt;br&gt;&lt;br&gt;

&lt;div class="tag"&gt;
--Tags:-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Russia" rel="tag"&gt;Russia&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-&lt;b&gt;[&lt;/b&gt;&lt;a href="http://www.technorati.com/tag/Oka" rel="tag"&gt;Oka&lt;/a&gt;&lt;b&gt;]&lt;/b&gt;-----------&lt;br&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5799246-113698564744894743?l=www.cofault.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.cofault.com/feeds/113698564744894743/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5799246&amp;postID=113698564744894743' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113698564744894743'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5799246/posts/default/113698564744894743'/><link rel='alternate' type='text/html' href='http://www.cofault.com/2006/01/visit-to-countryside.html' title='A visit to the countryside.'/><author><name>nikita</name><uri>http://www.blogger.com/profile/09403336533089968821</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='31' height='26' src='http://3.bp.blogspot.com/_QCNNSTdukHs/ScpFFFtSecI/AAAAAAAAFl4/I3rzkBZBNcY/S220/ein-fritz-lang-film.jpg'/></author><thr:total>0</thr:total></entry></feed>
