CPL 2016, week 11 Clojure immutable data structures Oleg Batrashev - - PowerPoint PPT Presentation

cpl 2016 week 11
SMART_READER_LITE
LIVE PREVIEW

CPL 2016, week 11 Clojure immutable data structures Oleg Batrashev - - PowerPoint PPT Presentation

CPL 2016, week 11 Clojure immutable data structures Oleg Batrashev Institute of Computer Science, Tartu, Estonia April 25, 2016 Overview Last week Clojure language core This week Immutable data structures Next weeks Clojure


slide-1
SLIDE 1

CPL 2016, week 11

Clojure immutable data structures Oleg Batrashev

Institute of Computer Science, Tartu, Estonia

April 25, 2016

slide-2
SLIDE 2

Overview

Last week

◮ Clojure language core

This week

◮ Immutable data structures

Next weeks

◮ Clojure simple state and design ◮ Software transactional memory ◮ Agents in Clojure

slide-3
SLIDE 3

Immutable data structures 27/74

  • Trees

◮ (defrecord tree [value left right]) – Java class with 3

immutable fields

◮ Having (tree. 3 :leaf (tree. 33 :leaf :leaf))

◮ want to replace 3 with 45

tree 3 leaf tree 33 leaf leaf

slide-4
SLIDE 4

Immutable data structures 27/74

  • Trees

◮ (defrecord tree [value left right]) – Java class with 3

immutable fields

◮ Having (tree. 3 :leaf (tree. 33 :leaf :leaf))

◮ want to replace 3 with 45

tree 3 leaf tree 33 leaf leaf tree 45

◮ need to create new node and point to the subtrees ◮ in general, path from root to node must be reconstructed ◮ whoever references (part of) the tree never sees any changes

slide-5
SLIDE 5

Immutable data structures 28/74

  • Immutable data structures

◮ “Purely functional data structures” (book)

◮ immutable – whoever has reference never sees any changes ◮ structural sharing – old instance shares data with the new one ◮ assymptotically (almost) as efficient as transient

implementations

◮ O(log32 n) for unsorted collections (vector,hash-map,hash-set) ◮ O(log2 n) for sorted collections (sorted-map,sorted-set) ◮ in Clojure referred as persistent collections

◮ transient counterparts

◮ handy for local,temporary operations, like StringBuffer

slide-6
SLIDE 6

Immutable data structures 29/74

  • Benefits

◮ may be safely

◮ passed to functions ◮ used as keys in maps and entries in sets

◮ enabling concurrency

◮ sharing collections between threads is safe

◮ free versioning

◮ old versions of the instance are untouched – may store them to

a sequence and use for undo

slide-7
SLIDE 7

Immutable data structures 30/74 Binary Tree -

Outline

Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map

slide-8
SLIDE 8

Immutable data structures 31/74 Binary Tree -

Definition

◮ A node in binary tree can be either

◮ a leaf – :leaf ◮ an internal node – with left and right subtrees

(defrecord Node [value left right ]) ◮ Ex: (Node. 15 :leaf (Node. 33 :leaf :leaf))

tree 15 leaf tree 33 leaf leaf

◮ More compactly

15 33

slide-9
SLIDE 9

Immutable data structures 32/74 Binary Tree -

Depth-first traversal

◮ Traverse left subtree then right subtree (defn dft [node] (if (= node :leaf) (println :leaf) (do (println (. value node )) (dft (. left node )) (dft (. right node ))))) ◮ by itself not specifically useful

◮ add accumulator

slide-10
SLIDE 10

Immutable data structures 33/74 Binary Tree -

DFT with accumulator

(defn - dft -acc -impl [node acc] (if (= node :leaf) acc (let [lAcc (dft -acc -impl (. left node) acc) cAcc (cons (. value node) lAcc) rAcc (dft -acc -impl (. right node) cAcc )] rAcc ))) (defn dft -acc [node] (reverse (dft -acc -impl node '()))) ◮ List accumulator

◮ grow from list head ◮ reverse at the end

slide-11
SLIDE 11

Immutable data structures 34/74 Binary Tree -

Breadth-first traversal

  • 1. put tree root node to a queue
  • 2. iteratively

2.1 take tree node from the queue 2.2 process node 2.3 put child nodes to the queue

◮ queue could be immutable (see below)

slide-12
SLIDE 12

Immutable data structures 35/74 Working with immutable data -

Outline

Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map

slide-13
SLIDE 13

Immutable data structures 36/74 Working with immutable data -

Accessing

◮ Having collection/object like (def d {:somekey 42}) access (d :somekey) (: somekey d) (. somekey d) (get d :somekey) (get -in d [: somekey ])

  • 1. works for lists and maps
  • 2. works for maps and records, may return nil
  • 3. works for records/types/objects, may throw

NullPointerException

  • 4. works for lists, maps and records
  • 5. multilevel get, may specify list of keys for several levels
slide-14
SLIDE 14

Immutable data structures 37/74 Working with immutable data -

“Update” immutable state

(assoc d :newkey 43 :key3 44) (conj d [: newkey 43]) (into d {: newkey 43}) (assoc -in d [: newkey 2 3] 43) ; -> {: somekey 42, :newkey {2 {3 43}}}

  • 1. assign new values, works with lists, maps, and records
  • 2. update elements, works with lists, maps
  • 3. update several elements (from another collection)
  • 4. multilevel update, works with maps and records

All of them return new object, because you are working on immutable structures!

slide-15
SLIDE 15

Immutable data structures 38/74 Binary search tree -

Outline

Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map

slide-16
SLIDE 16

Immutable data structures 39/74 Binary search tree -

Definition

◮ binary search tree (ordered binary tree)

◮ values in ◮ left subtree are smaller ◮ right subtree are larger

15 6 3 8 33

slide-17
SLIDE 17

Immutable data structures 40/74 Binary search tree -

Lookup

(defn lookup [node v] (if (= node :leaf) :not -found (let [nodeV (. value node )] (cond (= v nodeV) v (< v nodeV) (lookup (. left node) v) (> v nodeV) (lookup (. right node) v))))) ◮ this is set, should have key&value to act as map

slide-18
SLIDE 18

Immutable data structures 41/74 Binary search tree -

Insertion

(defn insert -1 [node v] (if (= :leaf node) (Node. v :leaf :leaf) (let [{nv :value nl :left nr :right} node] (if (< v nv) (Node. nv (insert -1 nl v) nr) (Node. nv nl (insert -1 nr v)) ))))

15 6 3 8 33

slide-19
SLIDE 19

Immutable data structures 41/74 Binary search tree -

Insertion

(defn insert -1 [node v] (if (= :leaf node) (Node. v :leaf :leaf) (let [{nv :value nl :left nr :right} node] (if (< v nv) (Node. nv (insert -1 nl v) nr) (Node. nv nl (insert -1 nr v)) ))))

15 6 3 8 7 33

slide-20
SLIDE 20

Immutable data structures 42/74 Binary search tree -

Insertion (2)

◮ Record may have many fields – we want to redefine one ◮ Record acts as a type (later) and as a dict

◮ use assoc as for dictionary ◮ record fields accessed by Keyword keys

(defn insert [node v] (if (= :leaf node) (Node. v :leaf :leaf) (if (< v (. value node )) (assoc node :left (insert (. left node) v)) (assoc node :right (insert (: right node) v)))))

slide-21
SLIDE 21

Immutable data structures 43/74 Binary search tree -

Deletion (1)

(defn remove -smallest [node] ;; Remove the smallest value from the tree and ;; return it with the node root. (when node (let [[Yp Tp] (remove -smallest (. left node ))] (if Yp [Yp (assoc node :left Tp)] [(. value node) (: right node )]))))

Y T1 T2 ? T1 T2 Yp Yp T1 Tp Yp

slide-22
SLIDE 22

Immutable data structures 44/74 Binary search tree -

Deletion (2)

  • 1. find v in tree
  • 2. cut nv2 (smallest) from right subtree nr
  • 3. put nv2 and nr2 into the place of node

(defn delete [{nv :value , nl :left , nr :right :as node} v] (cond (nil? node) nil ;; recurse into left/right subtree , reconstruct new tree (< v nv) (Node. nv (delete nl v) nr) (> v nv) (Node. nv nl (delete nr v)) ;; found the nvalue , return it and cut the right subtree (= v nv) (let [[ nv2 nr2] (remove -smallest nr)] (if -not (nil? nv2) ; is right subtree non -empty? (Node. nv2 nl nr2) nl)) ))

slide-23
SLIDE 23

Immutable data structures 45/74 Balanced BST -

Outline

Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map

slide-24
SLIDE 24

Immutable data structures 46/74 Balanced BST -

Overview

◮ Balanced binary search tree

◮ binary search tree ◮ complexities ◮ lookup O(log n) ◮ insertion O(log n) ◮ deletion O(log n) ◮ iterate over elements O(n)

◮ Variants

◮ Red-black tree ◮ AVL tree ◮ others

slide-25
SLIDE 25

Immutable data structures 47/74 Balanced BST -

Red-black tree: definition

  • 1. A node is either red or black
  • 2. Root node is black
  • 3. All leaves are black
  • 4. Both children of every red node are black
  • 5. Same number of black nodes in each path from the root to a

leaf 15 6 3 8 33 Property

◮ the longest path is less than 2 times the shortest path

◮ hint: shortest must be all blacks

slide-26
SLIDE 26

Immutable data structures 48/74 Balanced BST -

Rotate

◮ left and right rotation if two nodes are red

◮ assume changes are made in A (B)

◮ right rotation

◮ if U and root of A (root of B) are both red ◮ change the color of the root A (root of B) to black ◮ preserves ordering

V U A B C U V A B C right rotate left rotate

slide-27
SLIDE 27

Immutable data structures 49/74 Balanced BST -

Rotate right: code

(defn - rotate -right -if -reds [{U :left C :right :as V}] (let [A (: left U) B (: right U)] (cond (or ; two cases when need to rotate (and (= (: color U) :red) (= (: color A) :red )) (and (= (: color U) :red) (= (: color B) :red ))) (assoc U :left (assoc A :color :black) :right (assoc V :left B)) :true V ; else do not rotate )))

slide-28
SLIDE 28

Immutable data structures 50/74 Balanced BST -

Rotate left: code

(defn - rotate -left -if -reds [{A :left V :right :as U}] (let [B (: left V) C (: right V)] (cond (or ; two cases when need to rotate (and (= (: color V) :red) (= (: color B) :red )) (and (= (: color V) :red) (= (: color C) :red ))) (assoc V :left (assoc U :right B) :right (assoc C :color :black )) :true U ; else do not rotate )))

slide-29
SLIDE 29

Immutable data structures 51/74 Balanced BST -

Insertion (1)

◮ insert red node as in binary search tree

◮ rotate if somewhere appear two red nodes

◮ leave black in the root (may appear red as the result of

rotation)

(defn insert [v T] (let [T2 (insert -and -rotate v T)] (assoc T2 :color :black )))

slide-30
SLIDE 30

Immutable data structures 52/74 Balanced BST -

Insertion (2)

◮ insert here if in leaf or found the location ◮ otherwise, insert new value into the left or right subtree

◮ try to rotate right or left correspondingly

(defn - insert -and -rotate [v T] (cond (nil? T) (Node. :red v nil nil) (= v (. value T)) T (< v (. value T)) (let [T2 (insert -and -rotate v (. left T))] (rotate -right -if -reds (assoc T :left T2 ))) (> v (. value T)) (let [T2 (insert -and -rotate v (. right T))] (rotate -left -if -reds (assoc T :right T2 ))) ))

slide-31
SLIDE 31

Immutable data structures 53/74 Other algorithms -

Outline

Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map

slide-32
SLIDE 32

Immutable data structures 54/74 Other algorithms -

Queue (1)

◮ queue may be represented as list, e.g. 1|4|5|nil

◮ adding or removing from head is easy and cheap ◮ adding or removing from tail requires full list copy

◮ alternative: queue with 2 lists

◮ Backward list is used to prepend elements to it ◮ Forward list is used to take elements from it ◮ queue = FList + reversed BList ◮ if forward list is empty it is replaced with reversed backward list

slide-33
SLIDE 33

Immutable data structures 55/74 Other algorithms -

Queue (2)

fun {New} queue(nil nil) end fun {IsEmpty Q} queue(FList BList) = Q in FList==nil andthen BList==nil end % append element to the queue proc {Append Q X ?Qn} queue(FList BList) = Q in Qn = queue(FList X|BList) end

slide-34
SLIDE 34

Immutable data structures 56/74 Other algorithms -

Queue (3)

% take element from the queue proc {Take Q ?X ?Qn} queue(FList BList) = Q in if FList\=nil then X = FList.1 Qn = queue(FList.2 BList) elseif BList\=nil then RBList in % reverse RBList = {Reverse BList} X = RBList.1 Qn = queue(RBList.2 nil) else raise app("List is empty") end end end

slide-35
SLIDE 35

Immutable data structures 57/74 Other algorithms -

Queue (4)

◮ new reference is created for the updated queue

% append elements Qu = {New} Qu2 = {Append Qu 3} Qu3 = {Append Qu2 1} Qu4 = {Append Qu3 2} {System.show Qu4} % take element X Qu5 = {Take Qu4 X} {System.show X} {System.show Qu5}

◮ easy undo

◮ store old references: immutable data structures make it

possible (same for trees!)

slide-36
SLIDE 36

Immutable data structures 58/74 Other algorithms -

Graphs

declarative model (as compared to non-declarative)

◮ traversing graph is possible

◮ complexity (usually) multiple of log n ◮ unless graph node ids can be stored in array

◮ changing graph may require copying the whole graph

◮ because of immutable data ◮ node references ◮ same problem for double linked list

slide-37
SLIDE 37

Immutable data structures 59/74 Persistent vector and map -

Outline

Immutable data structures Binary Tree Working with immutable data Binary search tree Balanced BST Other algorithms Persistent vector and map

slide-38
SLIDE 38

Immutable data structures 60/74 Persistent vector and map -

Persistent vector

◮ http://en.wikipedia.org/wiki/Trie ◮ see (link) Understanding Clojure’s PersistentVector

implementation

◮ tree with 32 children, elements stored from leftmost to the

right

◮ 2-level may store 322 = 1024 elements ◮ 6-level may store 326 = 230 elements

◮ expands as necessary – adding to the end is cheap ◮ tail data optimization – store tail to separate buffer until

exceeds 32 elements

slide-39
SLIDE 39

Immutable data structures 61/74 Persistent vector and map -

Persistent map

Persistent hashmap

◮ similar ideas as in Persistent vector ◮ see http://blog.higher-order.net/2009/09/08/understanding-

clojures-persistenthashmap-deftwice Persistent sorted map

◮ implementation is immutable balanced search tree (def m (sorted -map 1 5 2 "z")) ; -> #'user/m m ; -> {1 5, 2 "z"} (m 1) ; -> 5 (type m) ; -> clojure.lang. PersistentTreeMap