• Stars
    star
    145
  • Rank 254,144 (Top 6 %)
  • Language
    Clojure
  • License
    Eclipse Public Li...
  • Created about 9 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Lean Hash Array Mapped Trie implementation in ClojureScript

Lean Hash Array Mapped Trie (Lean Map)

A ClojureScript implementation of Lean Hash Array Mapped Tries. See reference.

Leiningen

[lean-map "0.4.0"]

Technical Terms

  • HAMT is Hash Array Mapped Trie

Primary Goals

  • See if Lean Hash Array Mapped Tries performs better then the current HAMT implementation in terms of code size, memory usage, or operation speed
  • Have a Property Test Suite that tests the current HAMT implementation and can be used to test the Lean HAMT
  • Have an benchmark suite testing maps of sizes (100, 10000, and 100000) for hash, assoc, dissoc, assoc!, and dissoc! operations
  • Be a nearly drop in replacement for the current HAMT implementation

Secondary Goals

  • Be a reference implementation of how to implement a Lean HAMT
  • Have detailed documentation about how the Lean HAMT differs from the current HAMT implementation

Current Status

All standard ClojureScript map functionality (assoc, dissoc, get, seq, reduce-kv, persistent!, and transient) have been implemented and passed Collection Check tests. The improved iteration has been implemented, the improved equality checking is the last feature that needs to be completed.

Performance

Here are the performance gains over the reference ClojureScript HAMT implementation

  • 2x for scanning over sequences (except in Firefox which has a 2x slowdown)
  • 2 - 4x for hashing maps
  • One order of magnitude for equality checking in the worst case (no structural sharing) and two orders of magnitude in the best case (structural sharing)

The other operations are comparable to ~25% slower then the reference implementation.

Use script/bench.sh the performance benchmarks JavaScript (creates benchmarks inresources/bench/app.js). The benchmarks are meant to run how ClojureScript runs tests

Main Ideas of the Paper

Consolidation of key values pairs and HAMT nodes

The primary idea behind the paper is changing the current HAMT node implementation from this

[key1, value1, null, <HAMT Node 1>, key2, value2, key3, value3, null, <HAMTNode 2>]

to this

[key1, value1, key2, value2, key3, value3, <HAMT Node 1>, <HAMT Node 2>]

consolidating the key value pairs and HAMT nodes instead of having them interspersed.

This leads to memory savings from not having to have a marker null in front of HAMT node.

Compaction on delete

The secondary idea is to have delete always return the most compact HAMT. For example deleting D from this HAMT

[A, <HAMT Node 1>] -> [<HAMT Node 2>, D] -> [B, C]

returns this HAMT

[A, <HAMT Node 1>] -> [<HAMT Node 2>] -> [B, C]

that has an unnecessary HAMT node (HAMT Node 2). Ideally the delete operation should return

[A, <HAMT Node 1>] -> [B, C]

removing the superfluous HAMT node

According to the paper this leads to an 80 to 100 percent speedup for iteration and equality checks and comparable to better performance on insertion, deletion, and lookup.

Usage

Lean HAMT's are implemented in the cljs.lean-map.core namespace. User functions live in the cljs.lean-map.util namespace. Here is documentation of their usage

  • set-maps-to-lean-map!

    Modifies the literal maps {} so that they become lean-maps instead of standard ClojureScript maps. Note this does not change the hash-map function to output lean-maps.

    Usage: (set-maps-to-lean-map!)

  • set-maps-to-cljs-map!

    Modifies the literal maps {} back to the default ClojureScript maps.

    Usage: (set-maps-to-cljs-map!)

  • using-lean-maps?

    Usage: (using-lean-maps?)

  • lean-map?

    Check if a map is a lean-map

    Usage: (lean-map? {0 0 1 1 2 2 3 3 4 4 5 5})

  • lean-map-seq?

    Check if a seq is a seq of a lean-map

    Usage: (lean-map? {0 0 1 1 2 2 3 3 4 4 5 5})

  • hash-map

    Copy of the ClojureScript hash-map function but returns a lean-map instead of a ClojureScript map.

    Usage: (hash-map 0 0 1 1 2 2 3 3 4 4 5 5)

  • empty

    An empty lean-map for use in place of {}

    Usage: (assoc empty :foo :bar)

Testing

To test on node use script/node-test.sh. For phantomjs use script/phantom-test. If you want to run tests with a custom engine use:

lein with-profile test doo <js environment> <name of test build e.g. "test">

For a custom test build add it to :cljsbuild in project.clj

Thanks

  • Bendyworks for letting me work on this

  • Michael J. Steindorfer and Jurgen J. Vinju for the Lean HAMT Paper

  • Use The Source for their reference implementation

  • Zach Tellman for writing Collection Check

  • Martin Klepsch for porting Collection Check to ClojureScript and Nicolás Berger for helping me get it setup

  • David Nolen for perf and profiling suggestions

License

Copyright © 2015 Peter Schuck

Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.

More Repositories

1

bwoken

iOS UIAutomation Test Runner
Ruby
443
star
2

api-server

A JSON API server written in Haskell
Haskell
66
star
3

TravisCI.app

Objective-C
52
star
4

caravan

Example app using Interpol
Ruby
42
star
5

conwip-modules

Conwip Modules helps automate dynamically loading ClojureScript modules
Clojure
19
star
6

ionic-rails-app

An example Ionic app to communicate with Rails.
HTML
19
star
7

cap-ml

Text Detection Capacitor Plugin
Swift
15
star
8

theme-default-haml

Spree with theme-default hamlized and sassed, with additional hooks defined
JavaScript
14
star
9

payroll

Track & analyze payroll in order to make informed decisions.
Ruby
13
star
10

featured_model

Cucumber step definitions to create model instances with dynamic attributes and associations.
Ruby
7
star
11

buffet

A sampling of the tastiest dotfiles, configurations, and aliases from across the internet
Shell
7
star
12

liveview-rich-text-editor-collab

A Phoenix LiveView backed rich text editor with collaboration feature
Elixir
7
star
13

elm-action-cable

Client-side Elm library for ActionCable, part of the Ruby on Rails suite
Elm
6
star
14

bent_template

rails templates bent to your will
Ruby
4
star
15

contracts

A collection of open-sourced contracts
4
star
16

concert-cam

Ruby
4
star
17

idkfa

Simple credentials loading
Ruby
4
star
18

spree-wholesale

Extension to Spree allowing for wholesale pricing on products
Ruby
3
star
19

docker-rails-app

A simple Rails app running on Docker
Ruby
3
star
20

latest.rb

Adds "latest" function to Rails templates
Ruby
2
star
21

fam-fam-icons-on-rails

Ruby
2
star
22

restaurant_week

An interactive map for Restaurant Week in Madison, WI
JavaScript
2
star
23

bendyworks.github.com

JavaScript
2
star
24

pig

A rack endpoint to view the latest commits in an environment.
Ruby
2
star
25

tic-tac-toe-webpack

A webpack demo that implements a game of tic-tac-toe
JavaScript
2
star
26

awesome_digest

Hacker News digest email sender thingamabob
Ruby
2
star
27

angular-donuts

Ruby
2
star
28

dotfiles

The Bendyworks dotfiles, managed by chezmoi
Shell
1
star
29

spree-theme-default-hamlized

Deprecated, use bendyworks/theme-default-haml
1
star
30

bendy-github-jam

Launchpad for a https://github.com/github/game-off-2016 game
JavaScript
1
star
31

tailwind-twin-demo

Demo `create-react-app` using tailwindcss and twin.macro
JavaScript
1
star
32

pairing_jams

sweet jams to jam out by whilst pair programming
1
star
33

space-mining

Lightning Talk for Scottish Ruby Conference 2012
1
star
34

make_music_madison

JavaScript
1
star
35

botfiles

bendyworks' bootstrap dotfiles
Ruby
1
star
36

clojure-brave-and-true

Solutions for Clojure for the Brave and True exercises
Clojure
1
star
37

thinkery

General repository for breakable (and hopefully useful)
Ruby
1
star
38

attribution

Spreading the bendyword, one project at a time.
JavaScript
1
star