Skip to content

Commit

Permalink
Bring API in closer alignment to existing Array API
Browse files Browse the repository at this point in the history
  • Loading branch information
exists-forall committed Mar 14, 2016
1 parent 9c21766 commit b601fa7
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 160 deletions.
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
elm-stuff
index.html
index.html
project.sublime-workspace

project.sublime-project
1 change: 0 additions & 1 deletion src/ControlUtils.elm
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
module ControlUtils
( untilJust
, whileJust
--, findIndex
) where

untilJust : (a -> Maybe b) -> (a -> a) -> a -> b
Expand Down
142 changes: 141 additions & 1 deletion src/CustomArray.elm
Original file line number Diff line number Diff line change
@@ -1,4 +1,27 @@
module CustomArray where
module CustomArray
( Array
, empty
, initialize
, repeat
, fromList
, isEmpty
, length
, get
, set
, append
, map
, mapAccumL -- new!
, indexedMap
, foldl
, foldr
, filter
, pushMany -- new!
, push
, toList
, toIndexedList

, visualize
) where

import Bitwise

Expand All @@ -8,6 +31,10 @@ import ListUtils
import TupleUtils
import ControlUtils

-- for visualization:
import Html exposing (Html)
import Html.Attributes as Attrs

type alias NodeData a =
{ height : Int
, children : Table (Child a)
Expand Down Expand Up @@ -54,6 +81,9 @@ maximumBranching = 2^maximumBranchingPo2 -- inclusive bound
maximumSearchError : Int
maximumSearchError = 1 -- 2

empty : Array a
empty = Leaf (Table.fromList [])

-- note: always returns `Nothing` for negative indices
findFrom : (a -> Bool) -> Int -> Table a -> Maybe (Int, a)
findFrom condition i table =
Expand Down Expand Up @@ -82,6 +112,10 @@ length array =
Leaf leaf ->
Table.length leaf

isEmpty : Array a -> Bool
isEmpty =
length >> (==) 0 -- TODO: This might warrant being special-cased for performance reasons

get : Int -> Array a -> Maybe a
get i array =
case array of
Expand Down Expand Up @@ -160,6 +194,49 @@ foldr f init array =
Leaf leaf ->
Table.foldr f init leaf

filter : (a -> Bool) -> Array a -> Array a
filter condition =
let
accumulate x =
if condition x
then push x
else identity
in
foldl accumulate empty

mapAccumL : (a -> b -> (b, c)) -> b -> Array a -> (b, Array c)
mapAccumL f init array =
case array of
Node node ->
let
foldChild child accum =
let (newAccum, mapped) = mapAccumL f accum child.array
in (newAccum, { child | array = mapped })
in
let (accum, mapped) = Table.mapAccumL foldChild init node.children
in (accum, Node { node | children = mapped })

Leaf leaf ->
let (accum, mapped) = Table.mapAccumL f init leaf
in (accum, Leaf mapped)

indexedMap : (Int -> a -> b) -> Array a -> Array b
indexedMap f =
let accumulate x i = (i + 1, f i x)
in snd << mapAccumL accumulate 0

toList : Array a -> List a
toList =
foldr (::) []

accumIndexedList : a -> (Int, List (Int, a)) -> (Int, List (Int, a))
accumIndexedList x (i, xs) =
(i - 1, (i - 1, x) :: xs)

toIndexedList : Array a -> List (Int, a)
toIndexedList array =
snd (foldr accumIndexedList (length array, []) array)

chunk : List a -> List (Table a)
chunk list =
case list of
Expand Down Expand Up @@ -217,6 +294,47 @@ fromList list =
|> List.map Leaf
|> ControlUtils.untilJust toSingleRoot subarraysToNodes

heightForLength : Int -> Int
heightForLength i =
if i <= 1
then 0
else 1 + heightForLength (i // maximumBranching)

initialize : Int -> (Int -> a) -> Array a
initialize len f =
let
--recurse : Int -> (Int, Int) -> Array a
recurse height (startIndex, endIndex) =
if height == 0
then Leaf (Table.initialize (\i -> f (i + startIndex)) (endIndex - startIndex))
else
let
_ = Debug.log "height" height
_ = Debug.log "bounds" (startIndex, endIndex)
childLength = Bitwise.shiftLeft 1 (maximumBranchingPo2 * height)
childCount = ceiling (toFloat (endIndex - startIndex) / toFloat childLength)
childBounds i =
( i * childLength + startIndex
, min ((i + 1) * childLength + startIndex) endIndex
)
child i =
let bounds = childBounds i
in
{ startIndex = fst bounds
, endIndex = snd bounds
, array = recurse (height - 1) bounds
}
children = Table.initialize child childCount
in
Node { height = height, children = children }
in
recurse (heightForLength len) (0, len)

repeat : Int -> a -> Array a
repeat count item =
initialize count (always item) -- TODO: This may warrant being special-cased for performance
-- in particular, this function can theoretically reuse many of its recursive results, resulting in O(log n) performance as opposed to the current O(n log n) (?) performance

type alias PushResult a =
{ extended : Array a
, overflowed : List (Array a)
Expand Down Expand Up @@ -274,6 +392,10 @@ pushMany newItems array =
subarraysToNodes
(subresult.extended :: subresult.overflowed)

push : a -> Array a -> Array a
push newItem =
pushMany [newItem] -- TODO: this might warrant being special-cased for performance reasons

append : Array a -> Array a -> Array a
append array1 array2 =
let (newArray1, newArray2) = append' (array1, array2)
Expand Down Expand Up @@ -545,3 +667,21 @@ getConcat tab1 tab2 i =
if i < Table.length tab1
then Table.get i tab1
else Table.get (i - Table.length tab1) tab2

-- Debug visualization:
visualize : Array a -> Html
visualize array =
case array of
Node node ->
Html.div [Attrs.style [("margin", "20px")]]
[ Html.span [Attrs.style [("font-weight", "bold")]] [Html.text "Node "]
, Html.text ("(" ++ toString node.height ++ ")")
, Html.div [Attrs.style [("border-left", "solid")]]
(List.map (visualize << .array) (Table.toList node.children))
]

Leaf leaf ->
Html.div [Attrs.style [("margin", "20px")]] -- (List.map (Html.text << (\s -> " " ++ s ++ " ") << toString) (Table.toList leaf))
[ Html.span [Attrs.style [("font-weight", "bold")]] [Html.text "Leaf "]
, Html.text (toString (Table.toList leaf))
]
176 changes: 19 additions & 157 deletions src/Main.elm
Original file line number Diff line number Diff line change
@@ -1,167 +1,29 @@
module Main where

import Html exposing (Html)
import Html.Attributes as Attrs

import NaiveTable as Table exposing (Table)
import Assume exposing (assumeJust)
import CustomArray as Array exposing (Array)

import ListUtils

--main =
-- ["foo", "bar", "baz"]
-- |> Table.fromList
-- |> Table.get 1
-- |> toString
-- |> Html.text

--main =
-- Just "Hello"
-- |> assumeJust "This is a test"
-- |> toString
-- |> Html.text

test : Array String
test =
Array.Node
{ height = 1
, children =
Table.fromList
[ { startIndex = 0
, endIndex = 3
, array = Array.Leaf (Table.fromList ["a", "b", "c"])
}
, { startIndex = 3
, endIndex = 5
, array = Array.Leaf (Table.fromList ["d", "e"])
}
, { startIndex = 5
, endIndex = 9
, array = Array.Leaf (Table.fromList ["f", "g", "h", "i"])
}
, { startIndex = 9
, endIndex = 11
, array = Array.Leaf (Table.fromList ["j", "k"])
}
]
}

visualize : Array a -> Html
visualize array =
case array of
Array.Node node ->
Html.div [Attrs.style [("margin", "20px")]]
[ Html.span [Attrs.style [("font-weight", "bold")]] [Html.text "Node "]
, Html.text ("(" ++ toString node.height ++ ")")
, Html.div [Attrs.style [("border-left", "solid")]]
(List.map (visualize << .array) (Table.toList node.children))
]

Array.Leaf leaf ->
Html.div [Attrs.style [("margin", "20px")]] -- (List.map (Html.text << (\s -> " " ++ s ++ " ") << toString) (Table.toList leaf))
[ Html.span [Attrs.style [("font-weight", "bold")]] [Html.text "Leaf "]
, Html.text (toString (Table.toList leaf))
]

--main =
-- test
-- |> Array.map ((++) "Hello! ")
-- |> visualize
-- [1, 2, 3]
-- |> Array.fromList
-- |> Array.pushMany [4, 5, 6, 7]
-- |> Array.visualize

--main =
-- --Array.initialize 100 identity
-- Array.initialize 256 (flip (%) 10)
-- |> Array.filter ((/=) 5)
-- |> Array.visualize
-- --|> Array.toIndexedList
-- --|> Array.mapAccumL (\x total -> (total + x, -x)) 0
-- --|> fst
-- --|> Array.visualize
-- --|> toString
-- --|> Html.text

--main =
-- Array.chunk [1, 2, 3, 4, 5, 6, 7, 8, 9]
-- |> toString
-- |> Html.text

--main = visualize test

--main =
-- [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100]
-- |> Array.fromList
-- --|> Array.set 42 100000
-- |> Array.pushMany [-1, -2, -3, -4, -5, -6, -7, -8, -1, -2, -3, -4, -5, -6, -7, -8, -1, -2, -3, -4, -5, -6, -7, -8, -1, -2, -3, -4, -5, -6, -7, -8]
-- |> visualize

--main =
-- ["foo", "bar", "baz"]
-- |> Array.fromList
-- |> Array.pushMany ["FOO", "BAR", "BAZ"]
-- |> Array.pushMany ["biz", "buzz", "quux"]
-- |> Array.pushMany ["FOO", "BAR", "BAZ"]
-- |> Array.pushMany ["biz", "buzz", "quux"]
-- |> Array.pushMany ["FOO", "BAR", "BAZ"]
-- |> Array.pushMany ["biz", "buzz", "quux"]
-- |> visualize

test1 =
{ height = 1
, children = Table.fromList
[ { startIndex = 0, endIndex = 4, array = Array.Leaf (Table.fromList ["a", "b", "c", "d"]) }
, { startIndex = 4, endIndex = 6, array = Array.Leaf (Table.fromList ["e", "f"]) }
]
}

test2 =
{ height = 1
, children = Table.fromList
[ { startIndex = 0, endIndex = 3, array = Array.Leaf (Table.fromList ["g", "h", "i"]) }
, { startIndex = 3, endIndex = 5, array = Array.Leaf (Table.fromList ["j", "k"]) }
, { startIndex = 5, endIndex = 7, array = Array.Leaf (Table.fromList ["l", "m"]) }
, { startIndex = 7, endIndex = 10, array = Array.Leaf (Table.fromList ["n", "o", "p"]) }
]
}

--main =
-- Array.append' (Array.fromList ["foo", "bar", "baz", "foo", "bar", "baz"], Array.fromList ["alpha", "beta", "gamma", "alpha", "beta", "gamma"])
-- |> snd
-- |> visualize

--main =
-- Array.analyzeSearchError (test1, test2)
-- |> toString
-- |> Html.text

range : Int -> Int -> List Int
range i j =
if i < j
then i :: range (i + 1) j
else []

--main =
-- --(Array.Node test1, Array.Node test2)
-- (Array.fromList (range 0 101), Array.fromList (range 101 200))
-- |> Array.append'
-- |> \(l, r) -> Html.span [] [ Html.div [] [ visualize l ], Html.div [] [ Html.text "-----" ], Html.div [] [ visualize r] ]

--|> always (Html.text "Hello")
--|> fst
--|> visualize

--main =
-- ['a', 'b', 'c']
-- |> ListUtils.splitAt 3
-- |> toString
-- |> Html.text

--main =
-- (Array.fromList (range 0 101), Array.fromList (range 101 200))
-- |> Array.append
-- |> List.map (flip Array.get)
-- --|> visualize

main =
let
a1 = Array.fromList (range 0 101)
a2 = Array.fromList (range 101 201)
a3 = Array.append a1 a2
a4 = Array.append a3 a1
in
--List.map (\i -> Array.get i a4 |> Maybe.map ((==) i)) (range 0 201)
--List.map (flip Array.get a4 >> assumeJust "") (range 0 302)
--|> toString
--|> Html.text
a4
|> visualize
--Array.initialize 25 identity
--|> Array.dropLeftOf 1
--|> Array.visualize
Array.append (Array.fromList [1..10]) (Array.fromList [101..111])
|> Array.visualize

0 comments on commit b601fa7

Please sign in to comment.