Dimitre's profileXSLT: Riding the challen...BlogListsNetwork Tools Help

Blog


    July 20

    The Swiss Army Knife of Data Structures ... in C#

    Actually, it is not a knife and is known under the name of Finger Tree.  Smile

     
    Update: In a personal communication with Eric Lippert it was revealed that, in his words:
     
    "I worked up a full implementation as well but I decided that it was too complicated to post in the blog. What I was really trying to get across was that immutable data structures were possible and not that hard; a full-on finger tree implementation was a bit too much for that purpose."
     
    I am happy to correct my post and acknowledge that a previous C# implementation did exist. Hopefully, Eric will publish his implementation.
    So, the work discussed here is most probably the first published Finger Tree  implementation in C#.

     

    Background:
    Created by Ralf Hinze and Ross Paterson in 2004, and based to a large extent on the work of Chris Okasaki on Implicit Recursive Slowdown and Catenable Double-Ended Queus, this data structure, to quote the abstract of the paper introducing Finger Trees, is:

    "a functional representation of persistent sequences supporting access to the ends in amortized constant time, and concatenation and splitting in time logarithmic in the size of the smaller piece. Representations achieving these bounds have appeared previously, but 2-3 finger trees are much simpler, as are the operations on them. Further, by defining the split operation in a general form, we obtain a general purpose data structure that can serve as a sequence, priority queue, search tree, priority search queue and more."

    Why the finger tree deserves to be called the Swiss knife of data structures can best be explained by again quoting the introduction of the paper:

    "The operations one might expect from a sequence abstraction include adding and removing elements at both ends (the deque operations), concatenation, insertion and deletion at arbitrary points, finding an element satisfying some criterion, and splitting the sequence into subsequences based on some property. Many efficient functional implementations of subsets of these operations are known, but supporting more operations efficiently is difficult. The best known general implementations are very complex, and little used.
    This paper introduces functional 2-3 finger trees, a general implementation that performs well, but is much simpler than previous implementations with similar bounds. The data structure and its many variations are simple enough that we are able to give a concise yet complete executable description using the functional programming language Haskell (Peyton Jones, 2003). The paper should be accessible to anyone with a basic knowledge of Haskell and its widely used extension to multiple-parameter type classes (Peyton Jones et al., 1997). Although the structure makes essential use of laziness, it is also suitable for strict languages that provide a lazy evaluation primitive.
    "

    Efficiency and universality are the two most attractive features of finger trees. Not less important is simplicity, as it allows easy understanding, straightforward implementation and uneventful maintenance.

    Stacks support efficient access to the first item of a sequence only, queues and deques support efficient access to both ends, but not to an randomly-accessed item. Arrays allow extremely efficient O(1) access to any of their items, but are poor at inserting, removal, splitting and concatenation. Lists are poor (O(N)) at locating a randomly indexed item.

    Remarkably, the finger tree is efficient with all these operations. One can use this single data structure for all these types of operations as opposed to having to use several types of data structures, each most efficient with only some operations.

    Note also the words functional and persistent, which mean that the finger tree is an immutable data structure.

    In .NET the IList<T> interface specifies a number of void methods, which change the list in-place (so the instance object is mutable). To implement an immutable operation one needs first to make a copy of the original structure (List<T>, LinkedList<T>, ..., etc). An achievement of .NET 3.5 and LINQ is that the set of new extension methods (of the Enumerable class) implement immutable operations.

    In the year 2008, Finger Tree implementations have been known only in a few programming languages: in Haskell, in OCaml, and in Scala. At least this is what the popular search engines say.

    What about a C# implementation? In February Eric Lippert had a post in his blog about finger trees. The C# code he provided does not implement all operations of a Finger Tree and probably this is the reason why this post is referred to by the Wikipedia only as "Example of 2-3 trees in C#", but not as an implementation of the Finger Tree data structure. Actually, he did have a complete implementation at that time (see the Update at the start of this post), but desided not to publish it.

    My modest contribution is what I believe to be the first published complete C# implementation of the Finger Tree data structure as originally defined in the paper by Hinze and Paterson (only a few exercises have not been implemented).

    Programming a Finger Tree in C# was as much fun as challenge. The finger tree structure is defined in an extremely generic way. At first I even was concerned that C# might not be sufficiently expressive to implement such rich genericity. It turned out that C# lived up to the challenge perfectly. Here is a small example of how the code uses multiple types and nested type constraints:

    // Types:

    //     U -- the type of Containers that can be split

    //     T -- the type of elements in a container of type U

    //     V -- the type of the Measure-value when an element is measured

    public class Split<U, T, V>
       
    where U : ISplittable<T, V>
           
    where T : IMeasured<V>

    {
    // ..........................................................
    }

    Another challenge was to implement lazy evaluation (the .NET term for this is "deferred execution") for some of the methods. Again, C# was up to the challenge with its IEnumerable interface and the ease and finesse of using the "yield return" statement.

    The net result: it was possible to write code like this:

    public override IEnumerable<T> ToSequence()
    {
         ViewL<T, M> lView = LeftView();
         yield return lView.head;

         foreach (T t in lView.ftTail.ToSequence())
              yield return t;
    }

    Another challenge, of course, was that one definitely needs to understand Hinze's and Ross' article before even trying to start the design of an implementation. While the text should be straightforward to anyone with some Haskell and functional programming experience, it requires a bit of concentration and some very basic understanding of fundamental algebraic concepts.  In the text of the article one will find a precise and simple definition of a Monoid. My first thought was that such academic knowledge would not really be necessary for a real-world programming task. Little did I know... It turned out that the Monoid plays a central role in the generic specification of objects that have a Measure.

    I was thrilled to code my own version of a monoid in C#:

    public class Monoid<T>

    {

      T theZero;

      
      public delegate T monOp(T t1, T t2);

     

      public monOp theOp;

     

      public Monoid(T tZero, monOp aMonOp)

      {

        theZero = tZero;

     

        theOp = aMonOp;

      }

     

      public T zero

      {

        get

        {

          return theZero;

        }

      }

    }

     

    Without going into too-much details, here is how the correct Monoids are defined in suitable auxiliary classes to be used in defining a Random-Access Sequence, Priority Queue and Ordered Sequence:

     

    public static class Size

    {

        public static Monoid<uint> theMonoid =

             new Monoid<uint>(0, new Monoid<uint>.monOp(anAddOp));

           

        public static uint anAddOp(uint s1, uint s2)

        {

            return s1 + s2;

        }

    }

     

     

    public static class Prio

    {

        public static Monoid<double> theMonoid =

             new Monoid<double>

                (double.NegativeInfinity,

                 new Monoid<double>.monOp(aMaxOp)

                 );

     

        public static double aMaxOp(double d1, double d2)

        {

            return (d1 > d2) ? d1 : d2;

        }

    }

     

     

     

    public class Key<T, V> where V : IComparable

    {

        public delegate V getKey(T t);

           

        // maybe we shouldn't care for NoKey, as this is too theoretic

        public V NoKey;

     

        public getKey KeyAssign;

     

        public Key(V noKey, getKey KeyAssign)

        {

            this.KeyAssign = KeyAssign;

        }

    }

     

    public class KeyMonoid<T, V> where V : IComparable

    {

        public Key<T, V> KeyObj;

     

        public Monoid<V> theMonoid;

     

        public V aNextKeyOp(V v1, V v2)

        {

            return (v2.CompareTo(KeyObj.NoKey) == 0) ? v1 : v2;

        }

     

        //constructor

        public KeyMonoid(Key<T, V> KeyObj)

        {

            this.KeyObj = KeyObj;

     

            this.theMonoid =

             new Monoid<V>(KeyObj.NoKey,

                           new Monoid<V>.monOp(aNextKeyOp)

                          );

        }

    }

     

     

    Yet another challenge was to be able to create methods dynamically, as currying was essentially used in the specification of finger trees with measures. Once again it was great to make use of the existing .NET 3.5 infrastructure. Below is my simple FP static class, which essentially uses the .NET 3.5 Func object and a lambda expression in order to implement currying:

     

    public static class FP

    {

      public static Func<Y, Z> Curry<X, Y, Z>
                (
    this Func<X, Y, Z> func, X x)

      {

        return (y) => func(x, y);

      }

    }

     

    And here is a typical usage of the currying implemented above:

     

    public T ElemAt(uint ind)

    {
      return treeRep.Split

    (new MPredicate<uint>

       (

          FP.Curry<uint, uint, bool>(theLessThanIMethod2, ind)

       ),

         0

          ).splitItem.Element;

    }

     

    Now, for everyone who have reached this point of my post, here is the link to the complete implementation.

    Be reminded once again that .NET 3.5 is needed for a successful build.

    In my next posts I will analyze the performance of this Finger Tree implementation and how it fares compared to existing implementations of sequential data structures as provided by different programming languages and environments.

    Comments (13)

    Please wait...
    Sorry, the comment you entered is too long. Please shorten it.
    You didn't enter anything. Please try again.
    Sorry, we can't add your comment right now. Please try again later.
    To add a comment, you need permission from your parent. Ask for permission
    Your parent has turned off comments.
    Sorry, we can't delete your comment right now. Please try again later.
    You've exceeded the maximum number of comments that can be left in one day. Please try again in 24 hours.
    Your account has had the ability to leave comments disabled because our systems indicate that you may be spamming other users. If you believe that your account has been disabled in error please contact Windows Live support.
    Complete the security check below to finish leaving your comment.
    The characters you type in the security check must match the characters in the picture or audio.

    To add a comment, sign in with your Windows Live ID (if you use Hotmail, Messenger, or Xbox LIVE, you have a Windows Live ID). Sign in


    Don't have a Windows Live ID? Sign up

    No namewrote:
    您需要二手液晶显示屏废旧液晶屏么?我们是不折不扣的二手液晶屏、旧液晶屏大批发商,长期大量供应可再利用的旧液晶屏。我公司提供的各种尺寸的二手液晶屏, 不同厚薄如笔记本屏,均已经过我们严格的分类,检验,测试流程。请访问协力液晶屏www.sceondhandlcd.com[bigeechcgbbaacie]
    Nov. 25
    Oct. 30
    Oct. 30
    Oct. 30
    Oct. 30
    Oct. 24
    No namewrote:

    Hi,Do you have used lcd screens, lcd monitor used, surplus lcds and scrap LCDs? Please go here:www.sstar-hk.com(Southern Stars).We are constantly buying re-usable LCD panels.The re-usable panels go through strictly designed process of categorizing, checking, testing, repairing and refurbishing before they are re-used to make remanufactured LCD displays and TV sets.Due to our recent breakthrough in testing and repairing technology of LCD, we can improve the value for your LCD panels. website:www.sstar-hk.com[jfecbbibccidai]

    Oct. 15
    No namewrote:
    HTML clipboard情趣用品,情趣用品,情趣用品,情趣用品,情趣,情趣,情趣,情趣,按摩棒,震動按摩棒,微調按摩棒,情趣按摩棒,逼真按摩棒,G點,跳蛋,跳蛋,跳蛋,性感內衣,飛機杯,充氣娃娃,情趣娃娃,角色扮演,性感睡衣,SM,潤滑液,威而柔,香水,精油,芳香精油,自慰套,自慰,性感吊帶襪,吊帶襪,情趣用品加盟AIO交友愛情館,情人歡愉用品,美女視訊,情色交友,視訊交友,辣妹視訊,美女交友,嘟嘟成人網,成人網站,A片,A片下載,免費A片,免費A片下載情人歡愉用品,情趣用品,成人網站,情人節禮物,情人節,AIO交友愛情館,情色,情色貼圖,情色文學,情色交友,色情聊天室,色情小說,七夕情人節,色情,情色電影,色情網站,辣妹視訊,視訊聊天室,情色視訊,免費視訊聊天,美女視訊,視訊美女,美女交友,美女,情色交友,成人交友,自拍,本土自拍,情人視訊網,視訊交友90739,生日禮物,情色論壇,正妹牆,免費A片下載,AV女優,成人影片,色情A片,成人論壇,情趣,免費成人影片,成人電影,成人影城,愛情公寓,成人影片,保險套,舊情人,微風成人,成人,成人遊戲,成人光碟,色情遊戲,跳蛋,按摩棒,一夜情,男同志聊天室,肛交,口交,性交,援交,免費視訊交友,視訊交友,一葉情貼圖片區,性愛,視訊,視訊聊天,A片,A片下載,免費A片,嘟嘟成人網愛情公寓,情色,舊情人,情色貼圖,情色文學,情色交友,色情聊天室,色情小說,一葉情貼圖片區,情色小說,色情,色情遊戲,情色視訊,情色電影,aio交友愛情館,色情a片,一夜情,辣妹視訊,視訊聊天室,免費視訊聊天,免費視訊,視訊,視訊美女,美女視訊,視訊交友,視訊聊天,免費視訊聊天室,情人視訊網,影音視訊聊天室,視訊交友90739,成人影片,成人交友,美女交友,微風成人,嘟嘟成人網,成人貼圖,成人電影,A片
    Oct. 12
    Oct. 6
    Oct. 6
    No namewrote:

    Hi,Do you have used lcd screens, lcd monitor used, surplus lcds and scrap LCDs? Please go here:www.sstar-hk.com(Southern Stars).We are constantly buying re-usable LCD panels.The re-usable panels go through strictly designed process of categorizing, checking, testing, repairing and refurbishing before they are re-used to make remanufactured LCD displays and TV sets.Due to our recent breakthrough in testing and repairing technology of LCD, we can improve the value for your LCD panels. website:www.sstar-hk.com[dejeajaefgjgae]

    Sept. 22
    No namewrote:
    To the global wow gold the cheapest wow power leveling under the cheapest single-site! -99416968927088
    Sept. 14
    No namewrote:

    Amberdigital Branch,Southern Stars Enterprises Co is specializing in the development and manufacturing of screen advertisings, digital sign, digital signages and LCDs. Established in 1996, we have explored and developed the international market with professionalism. We have built a widespread marketing network, and set up a capable management team dedicated to provide beyond-expectation services to our customers.

    amberdigital Contact Us
    Southern Stars Enterprises Co (Hong Kong Office)
    Add:3 Fl, No.2, Lane 2, Kam Tsin Tsuen, Sheung Shui, Hong Kong
    Tel:+852 2681 4099
    Fax:+852 2681 4586

    Southern Stars Enterprises Co (Shenzhen Office)
    Add:DE, 16/F, Building 2, Nanguo Tower, Sungang Road, Shenzhen, China
    Tel:+86 755 2592 9100
    Fax:+86 755 2592 7171

    E-mail:sstar@netvigator.com
    website:www.amberdigital.com.hk
    alibaba:amberdigital.en.alibaba.com[cda

    Aug. 24

    Trackbacks

    The trackback URL for this entry is:
    http://dnovatchev.spaces.live.com/blog/cns!44B0A32C2CCF7488!582.trak
    Weblogs that reference this entry
    • None