@@ -20,6 +20,7 @@ import Properties.RangeProperties
2020
2121import Insertion
2222
23+ import Linear. Common
2324# ifdef MUTABLE_ARRAYS
2425import qualified Unsafe. Linear as Unsafe
2526import Array. Mutable as A
@@ -41,27 +42,33 @@ import qualified Array as A
4142{- @ quickSort :: xs:(Array a) -> { ys:(Array a) | isSorted' ys && A.size xs == A.size ys &&
4243 toBag xs == toBag ys } @-}
4344-- quickSort :: (Ord a, Show a) => Array a -> Array a
44- quickSort :: (HasPrimOrd a , Show a ) => Array a -> Array a
45+ quickSort :: (HasPrimOrd a , Show a ) => Array a -. Array a
4546quickSort xs =
46- let (n, xs1) = A. size2 xs in
47+ let (Ur n, xs1) = A. size2 xs in
4748 if n == 0 then xs1
48- else let (hd, xs2) = A. get2 xs1 0
49- {- @ promise :: { tmp:(Array a) | size tmp == n }
50- -> { out:(Ur (Array a)) | size (unur out) == n &&
51- toSlice (unur out) 0 n == toSlice xs2 0 n} @-}
52- promise tmp = Ur (A. copy xs2 0 tmp 0 n)
53- ? lem_copy_equal_slice xs2 0 tmp 0 n
54- {- @ cpy :: { ys:(Array a) | size ys == n && toSlice ys 0 n == toSlice xs2 0 n } @-}
55- Ur cpy = A. alloc n hd (Unsafe. toLinear promise)
56- in quickSortBtw (cpy ? lem_equal_slice_bag xs2 cpy 0 n) 0 n
49+ else let (Ur hd, xs2) = A. get2 0 xs1
50+ tmp = makeArray n hd in
51+ A. copy2 0 0 n xs2 tmp ? lem_copy_equal_slice xs2 0 tmp 0 n & \ (xs2', cpy0) ->
52+ (A. free(xs2'), cpy0) & \ (() , cpy) ->
53+ quickSortBtw 0 n (cpy ? lem_equal_slice_bag xs2 cpy 0 n)
54+ {-# INLINABLE quickSort #-}
55+
56+ {- @ quickSort' :: xs:(Array a) -> { ys:(Array a) | isSorted' ys && A.size xs == A.size ys &&
57+ toBag xs == toBag ys } @-}
58+ quickSort' :: (HasPrimOrd a , Show a ) => Array a -. Array a
59+ quickSort' xs =
60+ let (Ur n, xs1) = A. size2 xs in
61+ if n == 0 then xs1
62+ else quickSortBtw 0 n xs1
63+ {-# INLINABLE quickSort' #-}
5764
5865{- @ quickSortBtw :: xs:(Array a) -> { i:Int | 0 <= i } -> { j:Int | i <= j && j <= A.size xs }
5966 -> { ys:(Array a) | isSortedBtw ys i j && A.size xs == A.size ys &&
6067 toSlice xs 0 i == toSlice ys 0 i &&
6168 toSlice xs j (A.size xs) == toSlice ys j (A.size xs) &&
6269 toBagBtw xs i j == toBagBtw ys i j } / [j - i] @-}
63- quickSortBtw :: HasPrimOrd a => Array a -> Int -> Int -> Array a
64- quickSortBtw xs i j =
70+ quickSortBtw :: HasPrimOrd a => Int -> Int -> ( Array a -. Array a )
71+ quickSortBtw i j xs =
6572 if j - i < 2 then xs else
6673 if j - i <= INSERTIONSIZE
6774 then let (xs_l, xs_cr) = A. splitAt i xs
@@ -101,9 +108,9 @@ quickSortBtw xs i j =
101108 ? lem_toSlice_slice xs i (A. size xs) (j- i) (A. size xs - i)
102109 === toSlice xs j (A. size xs)
103110 )
104- else let (xs', i_piv) = shuffleBtw xs i j -- isPartitionedBtw xs' i i_piv j
105- xs'' = quickSortBtw xs' i i_piv
106- xs''' = quickSortBtw xs'' (i_piv + 1 ) j
111+ else let (xs', Ur i_piv) = shuffleBtw i j xs
112+ xs'' = quickSortBtw i i_piv xs'
113+ xs''' = quickSortBtw (i_piv + 1 ) j xs''
107114 ? lem_qs_pres_partition_left xs' xs'' i i_piv j
108115 in xs''' ? lem_sorted_partitions xs''' i i_piv (j
109116 ? lem_equal_slice_sorted xs'' xs''' 0 i i_piv (i_piv+ 1 )
@@ -116,66 +123,74 @@ quickSortBtw xs i j =
116123 ? lem_equal_slice_bag xs'' xs''' i (i_piv+ 1 )
117124 ? lem_toBagBtw_compose xs' xs'' i i_piv j
118125 ? lem_toBagBtw_compose xs'' xs''' i (i_piv+ 1 ) j
126+ {-# INLINE quickSortBtw #-}
119127
120- {- @ shuffleBtw :: xs:(Array a) -> { i:Int | 0 <= i } -> { j:Int | i + 1 < j && j <= A.size xs }
121- -> (Array a, Int)<{\ys ip -> isPartitionedBtw ys i ip j &&
128+ {- @ shuffleBtw :: { i:Int | 0 <= i } -> j:Int -> { xs:(Array a) | i + 1 < j && j <= A.size xs }
129+ -> (Array a, Ur Int)<{\ys ip -> isPartitionedBtw ys i (unur ip) j &&
122130 toSlice xs 0 i == toSlice ys 0 i &&
123131 toSlice xs j (A.size xs) == toSlice ys j (A.size xs) &&
124132 toBagBtw xs i j == toBagBtw ys i j &&
125- i <= ip && ip < j && A.size ys == A.size xs }> @-}
126- shuffleBtw :: HasPrimOrd a => Array a -> Int -> Int -> (Array a , Int )
127- shuffleBtw xs i j =
133+ i <= unur ip && unur ip < j && A.size ys == A.size xs }> @-}
134+
135+ shuffleBtw :: forall a . HasPrimOrd a => Int -> Int -> (Array a -. (Array a , Ur Int ))
136+ shuffleBtw i j xs = xs & A. get2 (j- 1 ) {- fix (j-1)^th element as the pivot -} & \ (Ur piv, xs1) ->
128137 let
129- (piv , xs1 ) = A.get2 xs (j - 1 ) -- fix xs[j-1] as the pivot
130- {-@ goShuffle :: { zs: (Array a) | get zs (j- 1 ) == piv && A. size zs == A. size xs &&
131- toBagBtw zs i j == toBagBtw xs i j &&
132- toSlice xs 0 i == toSlice zs 0 i &&
133- toSlice xs j (A. size zs) == toSlice zs j (A. size zs)}
134- -> { jl:Int | i <= jl && rangeUpperBound zs i jl piv }
135- -> { jr:Int | jl <= jr+ 1 && jr < j- 1 && rangeLowerBound zs (jr+ 1 ) (j- 1 ) piv }
136- -> (Array a , Int )< {\ ws ip -> rangeUpperBound ws i ip piv &&
137- rangeLowerBound ws ip (j- 1 ) piv &&
138- A. size ws == A. size zs &&
139- get ws (j- 1 ) == get zs (j- 1 ) &&
140- toBagBtw zs i j == toBagBtw ws i j &&
141- toBagBtw xs i j == toBagBtw ws i j &&
142- toSlice zs 0 i == toSlice ws 0 i &&
143- toSlice zs j (A. size zs) == toSlice ws j (A. size zs) &&
144- i <= ip && ip < j }> / [jr - jl + 1 ] @-}
145- -- at return, all of ws[i:ip] <= ws[j-1] and all of ws[ip:j-1] > ws[j-1].
146- goShuffle zs jl jr = -- BOTH bounds inclusive here
147- if jl > jr
148- then (zs, jl)
149- else let (vl, zs') = A. get2 zs jl in
150- if vl <= piv
151- then goShuffle zs' (jl+ 1 ? lem_rangeProperty_build_right zs (belowPivot (get zs (j- 1 )))
152- i (jl ? toProof (belowPivot (get zs (j- 1 )) (get zs jl))))
153- jr
154- else let (vr, zs'') = A. get2 zs' jr in
155- if vr > piv
156- then goShuffle zs'' jl (jr- 1 )
157- else let zs''' = swap zs'' jl jr
158- ? lem_range_outside_swap zs i jl jr (j- 1 ) piv
159- ? lma_swap zs jl jr
160- ? lma_swap_eql zs jl jr (j- 1 )
161- ? lem_bagBtw_swap zs i jl jr j
162- ? lem_toSlice_swap zs i jl jr j
163- in goShuffle zs''' jl (jr- 1 )
138+ {-@ goShuffle ::
139+ { jl: Int | i <= jl }
140+ -> { jr:Int | jl <= jr+ 1 }
141+ -> { zs:(Array a ) | get zs (j- 1 ) == piv && A. size zs == A. size xs &&
142+ toBagBtw zs i j == toBagBtw xs i j &&
143+ toSlice xs 0 i == toSlice zs 0 i &&
144+ toSlice xs j (A. size zs) == toSlice zs j (A. size zs)
164145
165- (xs', ip) = goShuffle xs1 i (j- 2 ) -- BOTH bounds inclusive
166- {- @ xs'' :: { vs:(Array a) | isPartitionedBtw vs i ip j &&
167- toSlice xs' 0 i == toSlice vs 0 i &&
168- toSlice xs' j (A.size xs') == toSlice vs j (A.size xs') &&
169- A.size xs' == A.size vs &&
170- toBagBtw xs i j == toBagBtw vs i j } @-}
171- xs'' = if ip < j- 1
172- then swap2 xs' ip (j- 1 ) ? lma_swap xs' ip (j- 1 )
173- ? lem_bagBtw_swap xs' i ip (j- 1 ) j
174- ? lem_range_inside_swap xs' ip (j- 1 )
175- ? lem_range_outside_swap xs' i ip (j- 1 ) j (get xs' (j- 1 ))
176- ? lem_toSlice_swap xs' i ip (j- 1 ) j
146+ && rangeUpperBound zs i jl piv
147+ && jr < j- 1 && rangeLowerBound zs (jr+ 1 ) (j- 1 ) piv }
148+ -> (Array a , Ur Int )< {\ ws ip -> rangeUpperBound ws i (unur ip) piv &&
149+ rangeLowerBound ws (unur ip) (j- 1 ) piv &&
150+ A. size ws == A. size zs &&
151+ get ws (j- 1 ) == get zs (j- 1 ) &&
152+ toBagBtw zs i j == toBagBtw ws i j &&
153+ toBagBtw xs i j == toBagBtw ws i j &&
154+ toSlice zs 0 i == toSlice ws 0 i &&
155+ toSlice zs j (A. size zs) == toSlice ws j (A. size zs) &&
156+ i <= unur ip && unur ip < j }> / [jr - jl + 1 ] @-}
157+ -- at return, all of ws[i:ip] <= ws[j-1] and all of ws[ip:j-1] > ws[j-1].
158+ goShuffle :: HasPrimOrd a => Int -> Int -> (Array a -. (Array a , Ur Int ))
159+ goShuffle jl jr zs = -- BOTH bounds inclusive here
160+ if jl > jr
161+ then (zs, Ur jl)
162+ else A. get2 jl zs & \ (Ur vl, zs') ->
163+ if vl <= piv
164+ then goShuffle (jl+ 1 ? lem_rangeProperty_build_right zs (belowPivot (get zs (j- 1 )))
165+ i (jl ? toProof (belowPivot (get zs (j- 1 )) (get zs jl))))
166+ jr zs'
167+ else A. get2 jr zs' & \ (Ur vr, zs'') ->
168+ if vr > piv
169+ then goShuffle jl (jr- 1 ) zs''
170+ else let zs''' = swap2 jl jr zs''
171+ ? lem_range_outside_swap zs i jl jr (j- 1 ) piv
172+ ? lma_swap zs jl jr
173+ ? lma_swap_eql zs jl jr (j- 1 )
174+ ? lem_bagBtw_swap zs i jl jr j
175+ ? lem_toSlice_swap zs i jl jr j
176+ in goShuffle jl (jr- 1 ) zs''' in
177+
178+ goShuffle i (j- 2 ) xs1 & \ (xs', Ur ip) -> -- BOTH bounds inclusive
179+ let
180+ {- @ xs'' :: { vs:(Array a) | isPartitionedBtw vs i ip j &&
181+ toSlice xs' 0 i == toSlice vs 0 i &&
182+ toSlice xs' j (A.size xs') == toSlice vs j (A.size xs') &&
183+ A.size xs' == A.size vs &&
184+ toBagBtw xs i j == toBagBtw vs i j } @-}
185+ xs'' = if ip < j- 1
186+ then swap2 ip (j- 1 ) xs' ? lma_swap xs' ip (j- 1 )
187+ ? lem_bagBtw_swap xs' i ip (j- 1 ) j
188+ ? lem_range_inside_swap xs' ip (j- 1 )
189+ ? lem_range_outside_swap xs' i ip (j- 1 ) j (get xs' (j- 1 ))
190+ ? lem_toSlice_swap xs' i ip (j- 1 ) j
177191 else xs'
178- in (xs'', ip)
192+ in (xs'', Ur ip)
193+ {-# INLINE shuffleBtw #-}
179194-- where
180195
181196 -- | This belongs in Equivalence.hs but causes a Fixpoint panic if it's there
0 commit comments