Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A take at updating Cryptol's sort function from insertion sort to merge sort #1302

Merged
merged 5 commits into from
Nov 29, 2021

Conversation

weaversa
Copy link
Collaborator

@weaversa weaversa commented Nov 4, 2021

Here we provide an implementation for sort that is much more computationally efficient than the current one. For example, sorting 3000 Integers takes ~4 seconds where the current implementation takes over a minute.

There are two variations on merging two sorted lists to choose from. They seem similar in terms of runtime and time it takes to prove a property.

…ge sort. This implementation is much more computationally efficient.
@weaversa
Copy link
Collaborator Author

weaversa commented Nov 6, 2021

I imagine that one of the two definitions of merge (or perhaps another candidate) would be preferred and moved under the scope of sortBy, removing the private block.

@robdockins
Copy link
Contributor

robdockins commented Nov 12, 2021

Are these sorts still stable? I know that was an important design consideration for the first version.

EDIT: some limited testing suggests that these are stable sorts.

@robdockins
Copy link
Contributor

On my machine, I'm seeing that the new sorts take about half the time as the current sort to sort a random [3000]Integer sequence. That's not the 15x speedup you seem to be seeing, though. I'm not sure what makes the difference.

@weaversa
Copy link
Collaborator Author

weaversa commented Nov 13, 2021

@robdockins Perhaps you didn't update the recursive calls to sortBy when you pulled out a standalone version to compare? Here's a standalone version:

/**
 * Sort a sequence of elements. Equivalent to 'sortBy (<=)'.
 */

sort' : {a, n} (Cmp a, fin n) => [n]a -> [n]a
sort' = sortBy' (<=)

/**
 * Sort a sequence according to the given less-than-or-equal relation.
 * The sorting is stable, so it preserves the relative position of any
 * pair of elements that are equivalent according to the order relation.
 */
sortBy' : {a, n} (fin n) => (a -> a -> Bit) -> [n]a -> [n]a
sortBy' le ((xs : [n/2]a) # (ys : [n/^2]a)) = merge le xs' ys'
  where
    xs' = if `(n/2)  == 1 then xs else sortBy' le xs
    ys' = if `(n/^2) == 1 then ys else sortBy' le ys

private

  merge : {a, n, m} (fin n, fin m)
   => (a -> a -> Bit) -> [n]a -> [m]a -> [n + m]a
  merge le xs ys = take zs.0
    where
      zs =
        [ if i == `n          then (ys@j, i  , j+1)
           | j == `m          then (xs@i, i+1, j  )
           | le (xs@i) (ys@j) then (xs@i, i+1, j  )
          else                     (ys@j, i  , j+1)
        | (_, i, j) <- [(undefined, 0, 0)] # zs
        ]

  merge' : {a, n, m} (fin n, fin m)
   => (a -> a -> Bit) -> [n]a -> [m]a -> [n + m]a
  merge' le xs ys =
      if `n == 0 \/ `m == 0 then xs # ys
       | le (xs@0) (ys@0)
      then drop`{1 - min 1 n} ([xs@0] # merge' le (drop`{min 1 n} xs) ys)
      else drop`{1 - min 1 m} ([ys@0] # merge' le xs (drop`{min 1 m} ys))

@robdockins
Copy link
Contributor

Well guessed, that's exactly what I did. Rookie mistake!

This seems like a great improvement to me. I guess I have a slight preference for merge over merge' based only on the look of it.

@weaversa
Copy link
Collaborator Author

Inlining the merge function seems to have sped things up even more.

@weaversa
Copy link
Collaborator Author

Should I update the failing tests by hand, or is there an automated way to do that?

@robdockins
Copy link
Contributor

No automation for that, unfortunately, other than copy/paste the suggested command line.

@weaversa
Copy link
Collaborator Author

@robdockins The CI passes and I don't envision any more work being done. Is there anything else you (or perhaps @brianhuffman) would like to see before considering a merge?

@robdockins
Copy link
Contributor

I'm happy. Any thoughts @brianhuffman ?

@yav
Copy link
Member

yav commented Nov 24, 2021

Seems reasonable to me. At some point we should really decide on the complexity of @, but probably not in this thread.

@robdockins robdockins merged commit 4ad8961 into master Nov 29, 2021
@RyanGlScott RyanGlScott deleted the mergeSort-Prelude branch March 22, 2024 14:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants