packages feed

tensort 0.1.0.0 → 0.2.0.0

raw patch · 25 files changed

+1241/−324 lines, 25 filesdep +QuickCheckdep ~basedep ~mtldep ~random

Dependencies added: QuickCheck

Dependency ranges changed: base, mtl, random, time

Files

CHANGELOG.md view
@@ -2,4 +2,24 @@  ## 0.1.0.0 -- 2024-05-30 -* First version. Released to an eager world.+* First version. Released to an eager world!++## 0.2.0.0 -- 2024-05-31++* Add Logarithmic Tensort++* Rename and update Exchangesort++* Simplify code and structure++* Cleanup exports++* Cleanup Types++* Improve documentation++* Add to package file++* Expand supported dependency versions++* Add tests
+ README.md view
@@ -0,0 +1,746 @@+# Tensort++Tensort is a tensor-based sorting algorithm that is tunable to adjust to +the priorities of the task at hand.++This project started as an exploration of what a sorting algorithm that +prioritizes robustness would look like. As such it also describes and provides+implementations of Robustsort, a group of Tensort variants designed to +prioritize Robustness in conditions defined in David H. Ackley's+[Beyond Efficiency](https://www.cs.unm.edu/~ackley/be-201301131528.pdf).++Note: This project is still under construction. The Library is +functional but I have yet to add documentation and benchmarking.+There's likely a lot of room for improvement in the code as well.++## Table of Contents++- [Introduction](#introduction)+  - [Inspiration](#inspiration)+  - [Why?](#why)+  - [Why Haskell?](#why-haskell)+- [Project structure](#project-structure)+- [Algorithms overview](#algorithms-overview)+  - [Tensort](#tensort-1)+    - [Preface](#preface)+    - [Structure](#structure)+    - [Algorithm](#algorithm)+    - [What are the benefits?](#what-are-the-benefits)+    - [Logarithmic Tensort](#logarithmic-tensort)+  - [Robustsort](#robustsort)+    - [Preface](#preface-1)+    - [Overview](#overview)+    - [Examining Bubblesort](#examining-bubblesort)+    - [Exchangesort](#exchangesort)+    - [Introducing Supersort](#introducing-supersort)+    - [Permutationsort](#permutationsort)+    - [Supersort Adjudication](#supersort-adjudication)+  - [Magicsort](#magicsort)+    - [Supersort adjudication with Magic](#supersort-adjudication-with-magic)+  - [A note on Robustsort and Bogosort](#a-note-on-robustsort-and-bogosort)+- [Comparing it all](#comparing-it-all)+- [Library](#library)++## Introduction++### Inspiration++  - [Beyond Efficiency](https://www.cs.unm.edu/~ackley/be-201301131528.pdf) by +  David H. Ackley+    +  - Future of Coding's +  [podcast episode](https://futureofcoding.org/episodes/070) on the same paper++### Why?++Because near the end of ^that podcast episode, +[Ivan Reese](https://github.com/ivanreese) said "Why are we +comparing Bubblesort versus Quicksort and Mergesort? Well, because no one's +made Robustsort yet." And I thought, "Why not?"++### But why would anyone care about this in the first place?++[Ackley](https://www.cs.unm.edu/~ackley/be-201301131528.pdf) has some really +compelling things to say about this, and I'd highly recommend you read that +paper!++Or listen to [this podcast](https://futureofcoding.org/episodes/070)!++If you want my elevator pitch, it's because we eventually want to build+[Dyson Spheres](https://en.wikipedia.org/wiki/Dyson_sphere). Doing so will +likely involve massively distributed systems being constantly pelted by +radiation. In circumstances like that, robustnesss is key.++Another other example I like to consider is artificial cognition. When working +in a non-determinative system (or a system so complex as to be considered+non-determinative), it can be helpful to have systems in place to make sure +that the answer we come to is really valid.++Incidentally, while I was preparing for this project, we experienced +[the strongest solar storm to reach Earth in 2 decades](https://science.nasa.gov/science-research/heliophysics/how-nasa-tracked-the-most-intense-solar-storm-in-decades/). +I don't know for certain whether the solar activity caused any computer errors, +but we had some anomalies at work and certainly joked about them being caused by+the Sun.++Also during the same period, +[one of the Internet's root-servers glitched out for unexplained reasons](https://arstechnica.com/security/2024/05/dns-glitch-that-threatened-internet-stability-fixed-cause-remains-unclear/).++As Ackley mentions, as a culture we have tended to prioritize correctness and +efficiency to the exclusion of robustness. The rate of our technological +progression precludes us from continuing to do so.++### Why Haskell?++[Obviously](https://www.youtube.com/shorts/LGZKXZQeEBg).++## Project structure++- `src/` contains the Tensort library+    +- `app/` contains the suite for comparing different sorting algorithms in terms of robustness and time efficiency++## Algorithms overview++This README assumes some general knowledge of basic sorting algoritms. If you+would like a refresher, I recommend +[this video](https://www.youtube.com/watch?v=kgBjXUE_Nwc) which touches on +Bubblesort, MergeSort, and Bogosort, and +[this video](https://www.youtube.com/watch?v=XE4VP_8Y0BU) which discusses+Quicksort.++It also assumes you've read +[Beyond Efficiency](https://www.cs.unm.edu/~ackley/be-201301131528.pdf) by +David H. Ackley. Go read it!++Please note that we will discuss a few algorithms that I've either made up or +am just not familiar with by other names. If any of these algorithms have +previously been named, please let me know. Prior to this project I really +only had a rudimentary understanding of Insertionsort, Quicksort, Mergesort,+Bubblesort and Bogosort, so it's entirely possible that I've reinvented a few +things that already exist.++It also may be helpful to note that this project was originally undertaken in+an endeavor to come up with a solution naively, for the practice, before +researching other algorithms built to tackle the same problem. I did very +briefly check out Ackley's +[Demon Horde Sort](https://www.youtube.com/watch?v=helScS3coAE&t=260s), +but only enough (about 5 seconds of that video) to verify that it is different +from this algorithm. I've been purposefully avoiding learning much about Demon +Horde Sort before publishing v1.0.0.0 of this package, but Ackley is way +smarter than me so if you do actually want a real, professional approach to +robust sorting, Demon Horde Sort is likely the place to look.++The algorithms used here that I have made up or renamed are, in order of +introduction, Tensort, Robustsort, Permutationsort, and Magicsort. Get ready!++### Tensort++#### Preface++Tensort is my attempt to write the most robust O(n log n) sorting algorithm +possible while avoiding anything that Ackley might consider a "cheap hack." +My hope is that it will be, if not competitive with Bubblesort in robustness, +at least a major improvement over Quicksort and Mergesort. ++Again, I'm not well-studied in sorting algorithms, so this may well be known +already under another name. After settling on this algorithm, I looked into +several other sorting algorithms for comparison and found a few that I think +are similar - significantly Blocksort, Bucketsort, and Patiencesort. If you are +familiar with these algorithms, you may recognize that they each have a +structure that aids in understanding them.++Tensort uses an underlying structure as well. We will discuss this structure +before going over the algorithm's actual steps. If this doesn't make sense yet,+fear not!++<!-- [image1] -->++#### Structure++  - Bit <- Element of the list to be sorted+    +  - Byte <- List of Bits++  - Bytesize <- Maximum length of a Byte+    +  - Tensor <- Tuple of a Register list and a Memory list+    +  - Memory <- List of Bytes or Tensors contained in the current Tensor.+    +  - Register <- List of Records referencing each Byte or Tensor in Memory+    +  - Record <- Tuple of the Address and the TopBit of the referenced Byte or Tensor+    +  - Address <- Pointer to a Byte or Tensor in Memory+    +  - TopBit <- Value of the Bit at the top of the stack in a Byte or Tensor++  - TensorStack <- A top-level Tensor along with all the Bits, Bytes, and Tensors it contains+    +  - SubAlgorithm <- The sorting sub-algorithm used at various stages++In Tensort, the smallest unit of information is a Bit. Each Bit stores one +element of the list to be sorted. A group of Bits is known as a Byte. ++A Byte is a list of Bits. The maximum length of a Byte is set according to an +argument passed to Tensort. In practice, almost all Bytes will be of maximum +length until the final steps of Tensort. Several Bytes are grouped together +in a Tensor.++A Tensor is a tuple with two elements: Register and Memory.++Memory is the second element in a Tensor tuple. It is a list of Bytes or +other Tensors. The length of this Memory list is equal to the Bytesize.++A Register is the first element in a Tensor tuple. It is a list of Records, +each of which has an Address pointing to an element in its Tensor's Memory +and a copy of the TopBit in the referenced element. These Records are arranged +in the order that the elements of the Tensor's Memory are sorted (this will be +clarified soon).++A TensorStack is a top-level Tensor along with all the Bits, Bytes, and +Tensors it contains. Once the Tensors are fully built, the total number +of TensorStacks will equal the Bytesize, but before that point there will +be many more TensorStacks.++The sorting SubAlgorithm will be used any time we sort something within +Tensort. The choice of this SubAlgorithm is very important. For reasons that +will become clear soon, the SubAlgorithm for Standard Tensort will be +Bubblesort, but the major part of Tensort's tunability is  the ability to +substitute another sorting algorithm based on current priorities.++Now, on to the algorithm!++#### Algorithm++The first step in Tensort is to randomize the input list. I'll explain why we +do this in more detail later - for now just know that it's easier for Tensort +to make mistakes when the list is already nearly sorted.++  1. Randomize the input list of elements (Bits)++  2. Assemble Bytes by sorting the Bits using the SubAlgorithm. After this, we +    will do no more write operations on the Bits until the final steps. Instead, we +    will make copies of the Bits and sort the copies alongside their pointers.++  3. Assemble TensorStacks by creating Tensors from the Bytes. Tensors are +    created by grouping Bytes together (setting them as the Tensor's +    second element), making Records from their top bits, sorting the records, and +    then recording the Pointers from the Records (after being sorted) as the +    Tensor's first element.++  4. Reduce the number of TensorStacks by creating a new layer of Tensors from +    the Tensors created in Step 3. These new Tensors are created by grouping +    the first layer of Tensors together (setting them as the new Tensor's +    second element), making Records from their top Bits, sorting the Records, and +    then recording the Pointers from the Records +    (after being sorted) as the Tensor's first element.++  5. Continue in the same manner as in Step 4 until the number of TensorStacks +    equals the Bytesize++  6. Assemble a top Register by Making Records from the Top Bits on each +    TensorStack and sort the Records.++  7. Remove the Top Bit from the top Byte in the top TensorStack and add it +    to the final Sorted List. If the top Byte has more than one But in it stll, +    Re-sort the Byte for good measure (technically this is +    running the algorithm on different arguments - if anyone wants to me about +    this I'll update this README)++  8. If the top Byte in the top TensorStack is empty, remove the Record that +    points to it from its Tensor's Register. If the Tensor is empty, remove+    the Record that points to it from its Tensor's Register. Do this recursively +    until the Tensor is not empty or the top of the TensorStack is reached. If the +    entire TensorStack is empty of Bits, remove its Record from the top Register. If +    all TensorStacks are empty of Bits, return the final Sorted List. Otherwise, +    re-sort the top Register++  9. Otherwise (the top Byte (or a Tensor that contains it) is not empty), +    update the top Byte's (or Tensor's) Record with its +    new Top Bit and re-sort its Tensor's Register. Then jump up a level to +    the Tensor that contains that Tensor and update the top Tensor's Record+    with its new Top Bit and re-sort its Register. Do this recursively until+    the whole TensorStack is rebalanced. Then update the TensorStack's Record in the +    top Register with its new Top Bit and re-sort the top Register.++Now that we know all the steps, it's easier to see why we randomize the list+as the beginning step. This way, if the list is already nearly +sorted, values close to each other don't get stuck under each other in their +Byte. Ideally, we want the top Bits from all TensorStacks to be close to +each other. Say for example, the first three elements in a 1,000,000-element +list are 121, 122, 123, and 124. If we don't randomize the list, these 3 +elements get grouped together in the first byte. That's all well and good if +everything performs as expected, but if something unexpected happens +during an operation where we intend to add 124 to the final list  +and we add a different element instead, three of the best-case elements to have+mistakenly added (121, 122, and 123) are impossible to have been selected.++#### What are the benefits?++The core idea of Tensort is breaking the input into smaller pieces along an +ever-expanding rank, and sorting the smaller pieces. Once we understand the+overall structure, we can design the SubAlgorithm (and Bytesize) to suit our +needs.++Standard Tensort leverages the robustness of Bubblesort while reducing the time +required by never Bubblesorting the entire input. ++We are able to do this because A) Bubblesort is really good at making sure the +last element is in the final position of a list, and B) at each step of Tensort +the only element we *really* care about is the last element in a given list +(or to look at it another way, the TopBit of a given Tensor).++#### Logarithmic Tensort++When using standard Tensort (i.e. using Bubblesort as the SubAlgoritm), as the +Bytesize approaches the square root of the number of elements in the +input list, its time efficiency approaches O(n^2).++Standard Tensort is most time efficient when the Bytesize is close +to the natural log of the number of elements in the input list. A logarithmic +Bytesize is likely to be ideal for most use cases of standard Tensort.++Alright! Now we have a simple sorting algorithm absent of cheap hacks that is +both relatively fast and relatively robust. I'm pretty happy with that!++<!-- [image2] -->++Now for some cheap hacks!++### Robustsort++#### Preface++In Beyond Efficiency, Ackley augmented Mergesort and Quicksort with what he +called "cheap hacks" in order to give them a boost in robustness to get them to +compare with Bubblesort. This amounted to adding a quorum system to the +unpredictable comparison operator and choosing the most-agreed-upon answer. ++I agree that adding a quorum for the unpredictable comparison operator is a bit +of a cheap hack, or at least a post-hoc solution to a known problem. Instead of +retrying a specific component again because we know it to be unpredictable, +let's build redundancy into the system at the (sub-)algorithmic level. A simple +way to do this is by asking different components the same question and see if +they agree.++Robustsort is my attempt to make the most robust sorting algorithm possible +utilizing some solution-checking on the (sub-)algorithmic level while still:++  - Keeping runtime somewhat reasonable++  - Never re-running a sub-algorithm that is expected to act deterministicly +      on the same arguments looking for a non-deterministic result (i.e. expect +      that if a components gives a wrong answer, running it again won't somehow +      yield a right answer)++  - Using a minimal number of different sub-algorithms (i.e. doesn't just +      use every O(n log n) sorting algorithm I can think of and compare all +      their results)++With those ground rules in place, let's get to Robustsort!++#### Overview++Once we have Tensort in our toolbox, the road to Robustsort is pretty simple. +Robustsort is a 3-bit Tensort with a custom SubAlgorithm that compares other +sub-algorithms. For convenience, we will call this custom SubAlgorithm +Supersort. We use a 3-bit Tensort here because there's something +magical that happens around these numbers.++Robust sorting algorithms tend to be +slow. Bubblesort, for example, has an average time efficiency of O(n^2), +compared with Quicksort and Mergesort, which both have an average of (n log n).++Here's the trick though: with small numbers the difference between these values +is minimal. For example, when n=4, Mergesort will make 6 comparisons, while +Bubblesort will make 12. A Byte holding 4 Bites is both small enough to run +the Bubblesort quickly and large enough to allow multiple opportunities for a +mistake to be corrected. Since we don't as much built-in parallelism in +Tensort, it can make sense to weight more heavily on the side of making more +checks.++In Robustsort, however, we have parallelism built into the Supersort +SubAlgorithm, so we can afford to make less checks during this step. +We choose a Bytesize of +3 because a list of+3 Bits has some special properties. For one thing, sorting at +this length greatly reduces the time it takes to run our slow-but-robust +algorithms. For example, at this size, Bubblesort will make only 6 comparisons. +Mergesort still makes 6 as well.++In addition, when making a mistake while sorting 3 elements, the mistake +will displace an element by only 1 or 2 positions at the, no matter which +algorithm is used.++This is all to say that using a 3-bit byte size allows us to have our pick of +algorithms to compare with!++Note: One might ask why we don't use a Bytesize of 2, since it would be even faster+and still have the same property of displacing an element by only 1 or 2+positions. Well, how many different algorithms can you use to sort 2 elements?+At this length, most algorithms function equivalently (in terms of the +sub-operations performed) and in my mind running two such algorithms is +equivalent to re-running a single algorithm (which violates the requirements +of this project).++#### Examining Bubblesort++Before moving further, let's talk a little about Bubblesort, and why we're +using it in our SubAlgorithm.++As a reminder, Bubblesort will make an average of 6 comparisons when sorting+a 3-element list.++We've said before that Bubblesort is likely to put the last element in the +correct position. Let's examine this in the context of Bubblesorting a +3-element list.++Our implementation of Bubblesort (which mirrors Ackley's) will perform three+iterations over a 3-element list. After the second iteration, if everything+goes as planned, the list will be sorted and the final iteration is an extra+verification step. Therefore, to simplify the analysis, we will consider+what happens with a faulty comparator during the final iteration, assuming the+list has been correctly sorted up to that point.++Given a Byte of [1,2,3], here are the chances of various outcomes from using a +faulty comparator that gives a random result 10% of the time:++    81% <- [1,2,3] (correct - no swaps made)++    9% <- [2,1,3] (faulty first swap)++    9% <- [1,3,2] (faulty second swap)++    1% <- [2,3,1] (faulty first and second swap)++In these cases, 90% of the time the Top Bit will be in the correct position, +and in the other cases it will be off by one position, and in no case will the +Byte be reverse sorted.++#### Exchangesort++When choosing an algorithm to compare with Bubblesort, we want something with +substantially different logic, for the sake of robustness. We do, +however, want something similar to Bubblesort in that it compares our elements +multiple times. And, as mentioned above, the element that is most important to +our sorting is the top (biggest) element, by a large degree.++With these priorities in mind, the comparison algorithm we choose shall be +Exchangesort. If you're not familiar with this algorithm, I'd recommend+checking out [this video](https://youtu.be/wqibJMG42Ik?feature=shared&t=143). ++The Exchangesort we use is notable in two ways. Firstly, it is a Reverse +Exchangesort, as explained in that video.++Secondly, the algorithm as described in the video only compares selected element +with elements that appear after (or before, as in Reverse Exchangesort) it in +the list, swapping them if the compared element is larger. This functions +similarly to an optimized Bubblesort where after the each round the last +element compared that round is no longer compared in following rounds. Our +implementation will compare the selected element with all other elements in the +list, swapping them if the element that appears later is larger. Ackley +uses an unoptimized Bubblesort in Beyond Efficiency, so I feel comfortable +using this variation for our Exchangesort.++Exchangesort will also make an average of 6 comparisons when sorting a+3-element list.++As with Bubblesort, Exchangesort will perform three iterations over a 3-element+list, with the final iteration being redundant.++Given a Byte of [1,2,3], here are the chances of various outcomes from using a +faulty comparator that gives a random result 10% of the time:++    81% <- [1,2,3] (correct - no swaps made)++    9% <- [2,1,3] (faulty first swap)++    9% <- [3,2,1] (faulty second swap)++    1% <- [3,1,2] (faulty first and second swap)++In these cases, 90% of the time the Top Bit will have the correct value. +Notably there is a 9% chance that the Byte will be reverse sorted, but we will +exploit this trait later on in the Supersort SubAlgorithm. Note also that the +only possible outcomes shared between this example and the Bubblesort example+are the correct outcome and [2,1,3], which retains the TopBit with the correct +value.++#### Introducing Supersort++Supersort is a SubAlgorithm that compares the results of two different+sorting algorithms, in our case Bubblesort and Exchangesort. If both +algorithms agree on the result, that result is used. ++Looking at our analysis on Bubblesort and Exchangesort, we can +approximate the chances of various outcomes when comparing the results of +running these two algorithms in similar conditions:++    65.61% <- [1,2,3], [1,2,3] (Agree Correctly)++    7.29% <- [1,2,3], [2,1,3] (Disagree - TopBit agrees correctly)++    7.29% <- [1,2,3], [3,2,1] (Disagree Fully)++    7.29% <- [2,1,3], [1,2,3] (Disagree - TopBit agrees correctly)++    7.29% <- [1,3,2], [1,2,3] (Disagree Fully)++    0.81% <- [2,1,3], [2,1,3] (Agree Incorrectly - TopBit correct)++    0.81% <- [2,1,3], [3,2,1] (Disagree Fully)++    0.81% <- [1,3,2], [2,1,3] (Disagree Fully)++    0.81% <- [1,3,2], [3,2,1] (Disagree Fully)++    0.09% <- [2,1,3], [3,1,2] (Disagree Fully)++    0.09% <- [1,3,2], [3,1,2] (Disagree - TopBit agrees incorrectly)++    0.09% <- [2,3,1], [2,1,3] (Disagree Fully)+  +    0.09% <- [2,3,1], [3,2,1] (Disagree - TopBit agrees incorrectly)++    0.01% <- [2,3,1], [3,1,2] (Disagree Fully)++In total, that makes:++    65.61% <- Agree Correctly++    17.2% <- Disagree Fully++    14.58% <- Disagree - TopBit agrees correctly++    0.81% <- Agree Incorrectly - TopBit correct++    0.18% <- Disagree - TopBit agrees incorrectly++    [no outcome] <- Agree with TopBit incorrect++The first thing that might stand out is that around 34% of the time, these +sub-algorithms will disagree with each other. What happens then?++Well, in that case we run a third sub-algorithm to compare the results with: +Permutationsort.++#### Permutationsort++Permutationsort is a simple, brute-force sorting algorithm. As a first step we +generate all the different ways the elements could possibly be arranged in the +list. Then we loop over this list of permutations until we find one that is in +the right order. We check if a permutation is in the right order by comparing+the first two elements, if they are in the right order comparing the next two+elements, and so on until we either find two elements that are out of order or+we confirm that the list is in order.++Permutationsort will also make an average of 7 comparisons when sorting a +3-element list. This is slightly more than the other algorithms examined but+it's worth it because A) the spread of outcomes is favorable for our needs, and +B) it uses logic that is completely different from Bubblesort and Exchangesort. +Using different manners of reasoning to reach an agreed-upon answer greatly +increases the robustness of the system.++Given a Byte of [1,2,3], here are the chances of various outcomes from using a+faulty comparator that gives a random result 10% of the time:++    ~68.67% <- [1,2,3] (correct)++    ~7.63% <- [2,1,3] (faulty first comparator)+  +    ~7.63% <- [3,1,2] (faulty first comparator)++    ~7.63% <- [1,3,2] (faulty second comparator)++    ~7.63% <- [2,3,1] (faulty second comparator)++    ~0.85% <- [3,2,1] (faulty first and second comparator)++In these cases, 76.6% of the time the Top Bit will be in the correct position. +Notably the least likely outcome is a reverse-sorted Byte and the other +possible incorrect outcomes are in even distribution with each other.++#### Supersort Adjudication++Supposing that our results from Bubblesort and Exchangesort disagree +and we now have our result from Permutationsort, how do we choose which to+use?++First we check to see whether the result from Permutationsort agrees with+the results from either Bubblesort or Exchangesort. To keep things +simple, let's just look at the raw chances that +Permutationsort will agree on results with Bubblesort or Exchangesort.++Permutationsort and Bubblesort:++    ~55.62% <- [1,2,3] (Correct)++    ~0.69% <- [2,1,3] (Correct TopBit)++    ~0.69% <- [1,3,2] (Incorrect)++    ~0.08% <- [2,3,1] (Incorrect)++Permutationsort and Exchangesort:++    ~55.62% <- [1,2,3] (Correct)++    ~0.69% <- [2,1,3] (Correct TopBit)++    ~0.08% <- [3,1,2] (Incorrect)++    ~0.08% <- [3,2,1] (Reverse)++As we can see, it is very unlikely that Permutationsort will agree with+either Bubblesort or Exchangesort incorrectly. It is even less likely+that they will do so when the TopBit is incorrect. However, there are many +cases in which they do not agree, so let's handle those.++If there is no agreed-upon result between these three algorithms, we will look +at the top bit only.++First we check if the results from Bubblesort and Exchangesort agree on the +TopBit. This is because the chance is very unlikely +(0.18%) that they will agree on an incorrect TopBit. If they do agree, we use +the result from Bubblesort (as it will not return a reverse-sorted list).++If they do not agree, we will check the TopBit results from Bubblesort and +Permutationsort. This is because it is unlikely +(~0.92%) that they will agree on an incorrect TopBit, and the chance of them +incorrectly agreeing on the highest Bit as the TopBit is even lower (~0.16%). +If they do agree, we use the result from Bubblesort.++If they do not agree, we will check the TopBit results from Exchangesort +and Permutationsort. The chance that they will agree on an +incorrect TopBit is about 1.55%, with the chances of them incorrectly agreeing+on the highest Bit as the TopBit also around 0.16%. If they do agree, we use+the result from Exchangesort.++If after all this adjudication we still do not have an agreed-upon result, we+will use the result from Bubblesort.++Now obviously we have made some approximations in our analysis (and I may have+made some mistakes in my calculations), but in general I think we can conclude +that it is very unlikely that this Supersort process will return an incorrect +result, and that if an incorrect result is returned, it is very likely to still +have a correct TopBit.++We now have the basic form of Robustsort: a 3-bit Tensort with a Supersort +adjudicating Bubblesort, Exchangesort, and Permutationsort as its+SubAlgorithm.++Well that's pretty cool! But I wonder... can we make this more robust, if +we relax the rules just a little more?++<!-- (image3) -->++Of course we can! And we will. To do so, we will simply replace Permutationsort+with another newly-named sorting algorithm: Magicsort!++### Magicsort++For our most robust iteration of Robustsort we will relax the requirement on+never re-running the same deterministic sub-algorithm in one specific context.+Magicsort is an algorithm that will re-run Permutationsort only if it disagrees +with an extremely reliable algorithm algorithm - one that's so good it's robust +against logic itself...++<!-- (image4) -->++Bogosort!++<!-- (image5) -->++Magicsort simply runs both Permutationsort and Bogosort on the same input and +checks if they agree. If they do, the result is used and if not, both +algorithms are run again. This process is repeated until the two algorithms+agree on a result.++Strong-brained readers may have already deduced that Permutationsort functions+nearly identically to Bogosort. Indeed, their approximate analysis results are+the same. Magicsort is based on the idea that if you happen to pull the right +answer out of a hat once, it might be random chance, but if you do it twice,+it might just be magic!++Given a Byte of [1,2,3], here are the approximate chances of various outcomes +from Magicsort using a faulty comparator that gives a random result 10% of the +time:++    ~95.27% <- [1,2,3] (Correct)++    ~1.18% <- [2,1,3] (Correct TopBit)++    ~1.18% <- [1,3,2] (Incorrect)++    ~1.18% <- [3,1,2] (Incorrect)++    ~1.18% <- [2,3,1] (Incorrect)++    ~0.02% <- [3,2,1] (Reverse)++The downside here is that Magisort can take a long time to run. I don't know +how many comparisons are made on average, but it's well over 14.++Thankfully, Magicsort will only be run in our algorithm if Bubblesort and+Exchangesort disagree on an answer. Overall the Robustsort we're building that +uses Magicsort will still have an average of O(n log n) time efficiency.++#### Supersort adjudication with Magic++Since we have replaced Permutationsort with Magicsort (which is far more robust +than Bubblesort or Exchangesort), we will adjust our adjudication+within the Supersort SubAlgorithm.++If Bubblesort and Exchangesort disagree, we will run Magicsort on the+input. If Magicsort agrees with either Bubblesort or Exchangesort, we+will use the result from Magicsort. Otherwise, if Magicsort agrees on the +TopBit with either Bubblesort or Exchangesort, we will use the result+from Magicsort. Otherwise, if Bubblesort and Exchangesort agree on the+TopBit, we will use the result from Bubblesort.++If no agreement is reached at this point, we abandon all logic and just use+Magicsort.++### A note on Robustsort and Bogosort++It is perfectly valid to use Bogosort in place of Permutationsort in Robustsort's +standard Supersort SubAlgorithm. It may be argued that doing so is even more +robust, since it barely even relies on logic. Here are some considerations to+keep in mind:++  - Permutationsort uses additional space and may take slightly longer on average +      due to computing all possible permutations of the input and storing them in a +      list.++  - Bogosort could theoretically run forever without returning a result, even +      when no errors occur.+  +## Comparing it all++Now let's take a look at how everything compares. Here is a graph showing the +benchmarking results in both in both robustness and time efficiency for +Quicksort, Mergesort, Standard Logarithmic Tensort, Robustsort (Permutations), +Robustsort (Bogo), Robustsort (Magic), and Bubblesort:++...Coming Soon!++## Library++This package contains implementations of each algorithm discussed above. +Notably, it provides the following:++  - Customizable Tensort++  - Standard Logarithmic Tensort++  - Standard Tensort with customizable Bytesize++  - Mundane Robustsort with Permutationsort adjudicator++  - Mundane Robustsort with Bogosort adjudicator++  - Magic Robustsort++Check the code in `src/` or the documentation on Hackage/Hoogle (Coming Soon!) +for more details.
app/Main.hs view
@@ -4,71 +4,61 @@ import Data.Tensort.OtherSorts.Quicksort (quicksort) import Data.Tensort.Robustsort (robustsortB, robustsortM, robustsortP) import Data.Tensort.Subalgorithms.Bubblesort (bubblesort)-import Data.Tensort.Tensort (tensortBasic2Bit, tensortBasic3Bit, tensortBasic4Bit)+import Data.Tensort.Tensort (tensortB4, tensortBL) import Data.Tensort.Utils.RandomizeList (randomizeList)-import Data.Tensort.Utils.Types (Sortable (..), fromSortInt)+import Data.Tensort.Utils.Types (Sortable (..), fromSortBit) import Data.Time.Clock -unsortedInts :: [Int]-unsortedInts = [2, 5, 10, 4, 15, 11, 7, 14, 16, 6, 13, 3, 8, 9, 12, 1]--unsortedInts52 :: Sortable-unsortedInts52 = randomizeList (SortInt [1 .. 52]) 143--unsortedInts1000 :: Sortable-unsortedInts1000 = randomizeList (SortInt [1 .. 1000]) 143--unsortedInts10000 :: Sortable-unsortedInts10000 = randomizeList (SortInt [1 .. 10000]) 143+unsortedBits :: [Int]+unsortedBits = [2, 5, 10, 4, 15, 11, 7, 14, 16, 6, 13, 3, 8, 9, 12, 1] -unsortedInts100000 :: Sortable-unsortedInts100000 = randomizeList (SortInt [1 .. 100000]) 143+genUnsortedBits :: Int -> Sortable+genUnsortedBits n = randomizeList (SortBit [1 .. n]) 143  main :: IO () main = do-  printTime unsortedInts52-  printTime unsortedInts1000-  printTime unsortedInts10000-  printTime unsortedInts100000+  printTimes (map genUnsortedBits [52, 1000, 10000, 50000, 100000]) +printTimes :: [Sortable] -> IO ()+printTimes [] = return ()+printTimes (x : xs) = do+  printTime x+  printTimes xs+ printTime :: Sortable -> IO () printTime l = do   putStr " Algorithm   | Time         | n ="-  startTensort2Bit <- getCurrentTime-  putStrLn (" " ++ show (length (tensortBasic2Bit (fromSortInt l))))-  endTensort2Bit <- getCurrentTime-  putStr (" Tensort2Bit | " ++ show (diffUTCTime endTensort2Bit startTensort2Bit) ++ " | ")-  startTensort3Bit <- getCurrentTime-  putStrLn ("    " ++ show (length (tensortBasic3Bit (fromSortInt l))))-  endTensort3Bit <- getCurrentTime-  putStr (" Tensort3Bit | " ++ show (diffUTCTime endTensort3Bit startTensort3Bit) ++ " | ")-  startTensort4Bit <- getCurrentTime-  putStrLn ("    " ++ show (length (tensortBasic4Bit (fromSortInt l))))-  endTensort4Bit <- getCurrentTime-  putStr (" Tensort4Bit | " ++ show (diffUTCTime endTensort4Bit startTensort4Bit) ++ " | ")+  startTensortB4 <- getCurrentTime+  putStrLn (" " ++ show (length (tensortB4 (fromSortBit l))))+  endTensortB4 <- getCurrentTime+  putStr (" Tensort4Bit | " ++ show (diffUTCTime endTensortB4 startTensortB4) ++ " | ")+  startTensortBL <- getCurrentTime+  putStrLn ("    " ++ show (length (tensortBL (fromSortBit l))))+  endTensortBL <- getCurrentTime+  putStr (" tensortBL   | " ++ show (diffUTCTime endTensortBL startTensortBL) ++ " | ")   startRSortP <- getCurrentTime-  putStrLn ("    " ++ show (length (robustsortP (fromSortInt l))))+  putStrLn ("    " ++ show (length (robustsortP (fromSortBit l))))   endRSortP <- getCurrentTime   putStr (" RobustsortP | " ++ show (diffUTCTime endRSortP startRSortP) ++ " | ")   startRSortB <- getCurrentTime-  putStrLn ("    " ++ show (length (robustsortB (fromSortInt l))))+  putStrLn ("    " ++ show (length (robustsortB (fromSortBit l))))   endRSortB <- getCurrentTime   putStr (" RobustsortB | " ++ show (diffUTCTime endRSortB startRSortB) ++ " | ")   startRSortM <- getCurrentTime-  putStrLn ("    " ++ show (length (robustsortM (fromSortInt l))))+  putStrLn ("    " ++ show (length (robustsortM (fromSortBit l))))   endRSortM <- getCurrentTime   putStr (" RobustsortM | " ++ show (diffUTCTime endRSortM startRSortM) ++ " | ")   startMergesort <- getCurrentTime-  putStrLn ("    " ++ show (length (fromSortInt (mergesort l))))+  putStrLn ("    " ++ show (length (fromSortBit (mergesort l))))   endMergesort <- getCurrentTime   putStr (" Mergesort   | " ++ show (diffUTCTime endMergesort startMergesort) ++ " | ")   startQuicksort <- getCurrentTime-  putStrLn ("    " ++ show (length (fromSortInt (quicksort l))))+  putStrLn ("    " ++ show (length (fromSortBit (quicksort l))))   endQuicksort <- getCurrentTime   putStr (" Quicksort   | " ++ show (diffUTCTime endQuicksort startQuicksort) ++ " | ")   startBubblesort <- getCurrentTime-  putStrLn ("    " ++ show (length (fromSortInt (bubblesort l))))+  putStrLn ("    " ++ show (length (fromSortBit (bubblesort l))))   endBubblesort <- getCurrentTime   putStr (" Bubblesort  | " ++ show (diffUTCTime endBubblesort startBubblesort) ++ " | ")-  putStrLn ("    " ++ show (length (fromSortInt (bubblesort l))))+  putStrLn ("    " ++ show (length (fromSortBit (bubblesort l))))   putStrLn "----------------------------------------------------------"
src/Data/Tensort/OtherSorts/Mergesort.hs view
@@ -1,29 +1,29 @@ module Data.Tensort.OtherSorts.Mergesort (mergesort) where -import Data.Tensort.Utils.ComparisonFunctions (lessThanInt, lessThanRecord)-import Data.Tensort.Utils.Types (Record, Sortable (..))+import Data.Tensort.Utils.ComparisonFunctions (lessThanBit, lessThanRecord)+import Data.Tensort.Utils.Types (Record, Sortable (..), Bit)  mergesort :: Sortable -> Sortable-mergesort (SortInt xs) = SortInt (mergesortInts xs)+mergesort (SortBit xs) = SortBit (mergesortBits xs) mergesort (SortRec xs) = SortRec (mergesortRecs xs) -mergesortInts :: [Int] -> [Int]-mergesortInts = mergeAllInts . map (: [])+mergesortBits :: [Bit] -> [Bit]+mergesortBits = mergeAllBits . map (: [])   where-    mergeAllInts [] = []-    mergeAllInts [x] = x-    mergeAllInts [x, y] = mergeInts x y-    mergeAllInts remaningElements = mergeAllInts (mergePairs remaningElements)+    mergeAllBits [] = []+    mergeAllBits [x] = x+    mergeAllBits [x, y] = mergeBits x y+    mergeAllBits remaningElements = mergeAllBits (mergePairs remaningElements) -    mergePairs (x : y : remaningElements) = mergeInts x y : mergePairs remaningElements+    mergePairs (x : y : remaningElements) = mergeBits x y : mergePairs remaningElements     mergePairs x = x -mergeInts :: [Int] -> [Int] -> [Int]-mergeInts [] y = y-mergeInts x [] = x-mergeInts (x : xs) (y : ys)-  | lessThanInt x y = x : mergeInts xs (y : ys)-  | otherwise = y : mergeInts (x : xs) ys+mergeBits :: [Bit] -> [Bit] -> [Bit]+mergeBits [] y = y+mergeBits x [] = x+mergeBits (x : xs) (y : ys)+  | lessThanBit x y = x : mergeBits xs (y : ys)+  | otherwise = y : mergeBits (x : xs) ys  mergesortRecs :: [Record] -> [Record] mergesortRecs = mergeAllRecs . map (: [])
src/Data/Tensort/OtherSorts/Quicksort.hs view
@@ -1,14 +1,14 @@ module Data.Tensort.OtherSorts.Quicksort (quicksort) where -import Data.Tensort.Utils.ComparisonFunctions (greaterThanInt, greaterThanRecord, lessThanOrEqualInt, lessThanOrEqualRecord)-import Data.Tensort.Utils.Types (Sortable (..), fromSortInt, fromSortRec)+import Data.Tensort.Utils.ComparisonFunctions (greaterThanBit, greaterThanRecord, lessThanOrEqualBit, lessThanOrEqualRecord)+import Data.Tensort.Utils.Types (Sortable (..), fromSortBit, fromSortRec)  quicksort :: Sortable -> Sortable-quicksort (SortInt []) = SortInt []-quicksort (SortInt (x : xs)) =-  let lowerPartition = quicksort (SortInt [a | a <- xs, lessThanOrEqualInt a x])-      upperPartition = quicksort (SortInt [a | a <- xs, greaterThanInt a x])-   in SortInt (fromSortInt lowerPartition ++ [x] ++ fromSortInt upperPartition)+quicksort (SortBit []) = SortBit []+quicksort (SortBit (x : xs)) =+  let lowerPartition = quicksort (SortBit [a | a <- xs, lessThanOrEqualBit a x])+      upperPartition = quicksort (SortBit [a | a <- xs, greaterThanBit a x])+   in SortBit (fromSortBit lowerPartition ++ [x] ++ fromSortBit upperPartition) quicksort (SortRec []) = SortRec [] quicksort (SortRec (x : xs)) =   let lowerPartition = quicksort (SortRec [a | a <- xs, lessThanOrEqualRecord a x])
src/Data/Tensort/Robustsort.hs view
@@ -9,25 +9,25 @@ import Data.Tensort.Subalgorithms.Bubblesort (bubblesort) import Data.Tensort.Subalgorithms.Magicsort (magicsort) import Data.Tensort.Subalgorithms.Permutationsort (permutationsort)-import Data.Tensort.Subalgorithms.ReverseExchangesort (reverseExchangesort)+import Data.Tensort.Subalgorithms.Exchangesort (exchangesort) import Data.Tensort.Subalgorithms.Supersort (magicSuperStrat, mundaneSuperStrat, supersort) import Data.Tensort.Tensort (mkTSProps, tensort)-import Data.Tensort.Utils.Types (Sortable)+import Data.Tensort.Utils.Types (Sortable, Bit) -robustsortP :: [Int] -> [Int]+robustsortP :: [Bit] -> [Bit] robustsortP xs = tensort xs (mkTSProps 3 supersortP)  supersortP :: Sortable -> Sortable-supersortP xs = supersort xs (bubblesort, reverseExchangesort, permutationsort, mundaneSuperStrat)+supersortP xs = supersort xs (bubblesort, exchangesort, permutationsort, mundaneSuperStrat) -robustsortB :: [Int] -> [Int]+robustsortB :: [Bit] -> [Bit] robustsortB xs = tensort xs (mkTSProps 3 supersortB)  supersortB :: Sortable -> Sortable-supersortB xs = supersort xs (bubblesort, reverseExchangesort, bogosort, mundaneSuperStrat)+supersortB xs = supersort xs (bubblesort, exchangesort, bogosort, mundaneSuperStrat) -robustsortM :: [Int] -> [Int]+robustsortM :: [Bit] -> [Bit] robustsortM xs = tensort xs (mkTSProps 3 supersortM)  supersortM :: Sortable -> Sortable-supersortM xs = supersort xs (bubblesort, reverseExchangesort, magicsort, magicSuperStrat)+supersortM xs = supersort xs (bubblesort, exchangesort, magicsort, magicSuperStrat)
src/Data/Tensort/Subalgorithms/Bubblesort.hs view
@@ -1,13 +1,13 @@ module Data.Tensort.Subalgorithms.Bubblesort (bubblesort) where -import Data.Tensort.Utils.ComparisonFunctions (lessThanInt, lessThanRecord)-import Data.Tensort.Utils.Types (Record, Sortable (..))+import Data.Tensort.Utils.ComparisonFunctions (lessThanBit, lessThanRecord)+import Data.Tensort.Utils.Types (Record, Sortable (..), Bit)  bubblesort :: Sortable -> Sortable-bubblesort (SortInt ints) = SortInt (foldr acc [] ints)+bubblesort (SortBit bits) = SortBit (foldr acc [] bits)   where-    acc :: Int -> [Int] -> [Int]-    acc x xs = bubblesortSinglePass x xs lessThanInt+    acc :: Bit -> [Bit] -> [Bit]+    acc x xs = bubblesortSinglePass x xs lessThanBit bubblesort (SortRec recs) = SortRec (foldr acc [] recs)   where     acc :: Record -> [Record] -> [Record]
+ src/Data/Tensort/Subalgorithms/Exchangesort.hs view
@@ -0,0 +1,31 @@+module Data.Tensort.Subalgorithms.Exchangesort (exchangesort) where++import Data.Tensort.Utils.ComparisonFunctions (greaterThanBit, greaterThanRecord)+import Data.Tensort.Utils.Types (Sortable (..))++exchangesort :: Sortable -> Sortable+exchangesort (SortBit bits) = SortBit (exchangesortIterable bits (length bits - 1) (length bits - 2) greaterThanBit)+exchangesort (SortRec recs) = SortRec (exchangesortIterable recs (length recs - 1) (length recs - 2) greaterThanRecord)++exchangesortIterable :: [a] -> Int -> Int -> (a -> a -> Bool) -> [a]+exchangesortIterable xs i j greaterThan = do+  if i < 0+    then xs+    else+      if j < 0+        then exchangesortIterable xs (i - 1) (length xs - 1) greaterThan+        else+          if ((i > j) && greaterThan (xs !! j) (xs !! i)) || ((j > i) && greaterThan (xs !! i) (xs !! j))+            then exchangesortIterable (swap xs i j) i (j - 1) greaterThan+            else exchangesortIterable xs i (j - 1) greaterThan++swap :: [a] -> Int -> Int -> [a]+swap xs i j = do+  let x = xs !! i+  let y = xs !! j+  let mini = min i j+  let maxi = max i j+  let left = take mini xs+  let middle = take (maxi - mini - 1) (drop (mini + 1) xs)+  let right = drop (maxi + 1) xs+  left ++ [y] ++ middle ++ [x] ++ right
src/Data/Tensort/Subalgorithms/Permutationsort.hs view
@@ -2,16 +2,16 @@  import Data.List (permutations) import Data.Tensort.Utils.Check (isSorted)-import Data.Tensort.Utils.Types (Record, Sortable (..), fromSortInt, fromSortRec)+import Data.Tensort.Utils.Types (Record, Sortable (..), fromSortBit, fromSortRec, Bit)  permutationsort :: Sortable -> Sortable-permutationsort (SortInt xs) = SortInt (acc (permutations x) [])+permutationsort (SortBit xs) = SortBit (acc (permutations x) [])   where     x = xs-    acc :: [[Int]] -> [Int] -> [Int]-    acc [] unsortedPermutations = fromSortInt (permutationsort (SortInt unsortedPermutations))+    acc :: [[Bit]] -> [Bit] -> [Bit]+    acc [] unsortedPermutations = fromSortBit (permutationsort (SortBit unsortedPermutations))     acc (permutation : remainingPermutations) unsortedPermutations-      | isSorted (SortInt permutation) = permutation+      | isSorted (SortBit permutation) = permutation       | otherwise = acc remainingPermutations unsortedPermutations permutationsort (SortRec xs) = SortRec (acc (permutations x) [])   where
− src/Data/Tensort/Subalgorithms/ReverseExchangesort.hs
@@ -1,29 +0,0 @@-module Data.Tensort.Subalgorithms.ReverseExchangesort (reverseExchangesort) where--import Data.Tensort.Utils.ComparisonFunctions (greaterThanInt, greaterThanRecord)-import Data.Tensort.Utils.Types (Sortable (..))--reverseExchangesort :: Sortable -> Sortable-reverseExchangesort (SortInt ints) = SortInt (reverseExchangesortIterable ints (length ints - 1) (length ints - 2) greaterThanInt)-reverseExchangesort (SortRec recs) = SortRec (reverseExchangesortIterable recs (length recs - 1) (length recs - 2) greaterThanRecord)--reverseExchangesortIterable :: [a] -> Int -> Int -> (a -> a -> Bool) -> [a]-reverseExchangesortIterable xs i j greaterThan = do-  if i < 1-    then xs-    else-      if j < 0-        then reverseExchangesortIterable xs (i - 1) (i - 2) greaterThan-        else-          if greaterThan (xs !! j) (xs !! i)-            then reverseExchangesortIterable (swap xs i j) i (j - 1) greaterThan-            else reverseExchangesortIterable xs i (j - 1) greaterThan--swap :: [a] -> Int -> Int -> [a]-swap xs i j = do-  let x = xs !! i-  let y = xs !! j-  let left = take j xs-  let middle = take (i - j - 1) (drop (j + 1) xs)-  let right = drop (i + 1) xs-  left ++ [y] ++ middle ++ [x] ++ right
src/Data/Tensort/Subalgorithms/Supersort.hs view
@@ -16,16 +16,16 @@     else superStrat (result1, result2, subAlg3 xs)  mundaneSuperStrat :: SupersortStrat-mundaneSuperStrat (SortInt result1, SortInt result2, SortInt result3) = do+mundaneSuperStrat (SortBit result1, SortBit result2, SortBit result3) = do   if result1 == result3 || result2 == result3-    then SortInt result3+    then SortBit result3     else       if last result1 == last result2 || last result1 == last result3-        then SortInt result1+        then SortBit result1         else           if last result2 == last result3-            then SortInt result2-            else SortInt result1+            then SortBit result2+            else SortBit result1 mundaneSuperStrat (SortRec result1, SortRec result2, SortRec result3) = do   if result1 == result3 || result2 == result3     then SortRec result3@@ -39,13 +39,13 @@ mundaneSuperStrat (_, _, _) = error "All three inputs must be of the same type."  magicSuperStrat :: SupersortStrat-magicSuperStrat (SortInt result1, SortInt result2, SortInt result3) = do+magicSuperStrat (SortBit result1, SortBit result2, SortBit result3) = do   if last result1 == last result3 || last result2 == last result3-    then SortInt result3+    then SortBit result3     else       if last result1 == last result2-        then SortInt result1-        else SortInt result3+        then SortBit result1+        else SortBit result3 magicSuperStrat (SortRec result1, SortRec result2, SortRec result3) = do   if last result1 == last result3 || last result2 == last result3     then SortRec result3
src/Data/Tensort/Tensort.hs view
@@ -1,41 +1,44 @@ module Data.Tensort.Tensort   ( tensort,-    tensortBasic2Bit,-    tensortBasic3Bit,-    tensortBasic4Bit,+    tensortB4,+    tensortBN,+    tensortBL,     mkTSProps,   ) where  import Data.Tensort.Subalgorithms.Bubblesort (bubblesort)+import Data.Tensort.Utils.Compose (createInitialTensors) import Data.Tensort.Utils.Convert (rawBitsToBytes) import Data.Tensort.Utils.RandomizeList (randomizeList) import Data.Tensort.Utils.Reduce (reduceTensorStacks)-import Data.Tensort.Utils.Render (getSortedBitsFromMetastack)-import Data.Tensort.Utils.Tensor (getTensorStacksFromBytes)-import Data.Tensort.Utils.Types (Sortable (..), TensortProps (..), fromSortInt)--mkTSProps :: Int -> (Sortable -> Sortable) -> TensortProps-mkTSProps bSize subAlg = TensortProps {bytesize = bSize, subAlgorithm = subAlg}--tensortBasic2Bit :: [Int] -> [Int]-tensortBasic2Bit xs = tensort xs (mkTSProps 2 bubblesort)--tensortBasic3Bit :: [Int] -> [Int]-tensortBasic3Bit xs = tensort xs (mkTSProps 3 bubblesort)--tensortBasic4Bit :: [Int] -> [Int]-tensortBasic4Bit xs = tensort xs (mkTSProps 4 bubblesort)+import Data.Tensort.Utils.Render (getSortedBitsFromTensor)+import Data.Tensort.Utils.Types (Sortable (..), TensortProps (..), fromSortBit, SortAlg, Bit) --- | Sort a list of Ints using the Tensort algorithm+-- | Sort a list of Bits using the Tensort algorithm  -- | ==== __Examples__ -- >>> tensort (randomizeList [1..100] 143) 2 -- [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]-tensort :: [Int] -> TensortProps -> [Int]+tensort :: [Bit] -> TensortProps -> [Bit] tensort xs tsProps = do-  let bits = randomizeList (SortInt xs) 143-  let bytes = rawBitsToBytes (fromSortInt bits) tsProps-  let tensorStacks = getTensorStacksFromBytes bytes tsProps-  let metastack = reduceTensorStacks tensorStacks tsProps-  getSortedBitsFromMetastack metastack (subAlgorithm tsProps)+  let bits = randomizeList (SortBit xs) 143+  let bytes = rawBitsToBytes (fromSortBit bits) tsProps+  let tensorStacks = createInitialTensors bytes tsProps+  let topTensor = reduceTensorStacks tensorStacks tsProps+  getSortedBitsFromTensor topTensor (subAlgorithm tsProps)++mkTSProps :: Int -> SortAlg -> TensortProps+mkTSProps bSize subAlg = TensortProps {bytesize = bSize, subAlgorithm = subAlg}++tensortB4 :: [Bit] -> [Bit]+tensortB4 xs = tensort xs (mkTSProps 4 bubblesort)++tensortBN :: Int -> [Bit] -> [Bit]+tensortBN n xs = tensort xs (mkTSProps n bubblesort)++tensortBL :: [Bit] -> [Bit]+tensortBL xs = tensort xs (mkTSProps (calculateBytesize xs) bubblesort)++calculateBytesize :: [Bit] -> Int+calculateBytesize xs = ceiling (log (fromIntegral (length xs)) :: Double)
src/Data/Tensort/Utils/Check.hs view
@@ -1,12 +1,12 @@ module Data.Tensort.Utils.Check (isSorted) where -import Data.Tensort.Utils.ComparisonFunctions (lessThanInt, lessThanRecord)+import Data.Tensort.Utils.ComparisonFunctions (lessThanOrEqualBit, lessThanOrEqualRecord) import Data.Tensort.Utils.Types (Sortable (..))  isSorted :: Sortable -> Bool-isSorted (SortInt []) = True-isSorted (SortInt [_]) = True-isSorted (SortInt (x : y : remainingElements)) = lessThanInt x y && isSorted (SortInt (y : remainingElements))+isSorted (SortBit []) = True+isSorted (SortBit [_]) = True+isSorted (SortBit (x : y : remainingElements)) = lessThanOrEqualBit x y && isSorted (SortBit (y : remainingElements)) isSorted (SortRec []) = True isSorted (SortRec [_]) = True-isSorted (SortRec (x : y : remainingElements)) = lessThanRecord x y && isSorted (SortRec (y : remainingElements))+isSorted (SortRec (x : y : remainingElements)) = lessThanOrEqualRecord x y && isSorted (SortRec (y : remainingElements))
src/Data/Tensort/Utils/ComparisonFunctions.hs view
@@ -1,29 +1,29 @@ module Data.Tensort.Utils.ComparisonFunctions-  ( lessThanInt,+  ( lessThanBit,     lessThanRecord,-    greaterThanInt,+    greaterThanBit,     greaterThanRecord,-    lessThanOrEqualInt,+    lessThanOrEqualBit,     lessThanOrEqualRecord,   ) where -import Data.Tensort.Utils.Types (Record)+import Data.Tensort.Utils.Types (Record, Bit) -lessThanInt :: Int -> Int -> Bool-lessThanInt x y = x < y+lessThanBit :: Bit -> Bit -> Bool+lessThanBit x y = x < y  lessThanRecord :: Record -> Record -> Bool lessThanRecord x y = snd x < snd y -greaterThanInt :: Int -> Int -> Bool-greaterThanInt x y = x > y+greaterThanBit :: Bit -> Bit -> Bool+greaterThanBit x y = x > y  greaterThanRecord :: Record -> Record -> Bool greaterThanRecord x y = snd x > snd y -lessThanOrEqualInt :: Int -> Int -> Bool-lessThanOrEqualInt x y = x <= y+lessThanOrEqualBit :: Bit -> Bit -> Bool+lessThanOrEqualBit x y = x <= y  lessThanOrEqualRecord :: Record -> Record -> Bool lessThanOrEqualRecord x y = snd x <= snd y
+ src/Data/Tensort/Utils/Compose.hs view
@@ -0,0 +1,97 @@+module Data.Tensort.Utils.Compose+  ( createInitialTensors,+    createTensor,+  )+where++import Data.Tensort.Utils.Split (splitEvery)+import Data.Tensort.Utils.Types (Byte, Memory (..), Record, SortAlg, Sortable (..), Tensor, TensortProps (..), fromSortRec, Bit)++-- | Convert a list of Bytes to a list of TensorStacks.++-- | This is accomplished by making a Tensor for each Byte, converting that+--   Tensor into a TensorStack (these are equivalent terms - see type+--   definitions for more info) and collating the TensorStacks into a list++-- | ==== __Examples__+--  >>> createInitialTensors [[2,4],[6,8],[1,3],[5,7]] 2+--  [([(0,3),(1,7)],ByteMem [[1,3],[5,7]]),([(0,4),(1,8)],ByteMem [[2,4],[6,8]])]+createInitialTensors :: [Byte] -> TensortProps -> [Tensor]+createInitialTensors bytes tsProps = foldr acc [] (splitEvery (bytesize tsProps) bytes)+  where+    acc :: [Byte] -> [Tensor] -> [Tensor]+    acc byte tensorStacks = tensorStacks ++ [getTensorFromBytes byte (subAlgorithm tsProps)]++-- | Create a Tensor from a Memory+--   Aliases to getTensorFromBytes for ByteMem and getTensorFromTensors for+--   TensorMem+createTensor :: Memory -> SortAlg -> Tensor+createTensor (ByteMem bytes) subAlg = getTensorFromBytes bytes subAlg+createTensor (TensorMem tensors) subAlg = getTensorFromTensors tensors subAlg++-- | Convert a list of Bytes to a Tensor++-- | We do this by loading the list of Bytes into the new Tensor's Memory+--   and adding a sorted Register containing References to each Byte in Memory++-- | Each Record contains an Address pointing to the index of the referenced+--   Byte and a TopBit containing the value of the last (i.e. highest) Bit in+--   the referenced Byte++-- | The Register is sorted by the TopBits of each Record++-- | ==== __Examples__+--  >>> getTensorFromBytes [[2,4,6,8],[1,3,5,7]]+--  ([(1,7),(0,8)],ByteMem [[2,4,6,8],[1,3,5,7]])+getTensorFromBytes :: [Byte] -> SortAlg -> Tensor+getTensorFromBytes bytes subAlg = do+  let register = acc bytes [] 0+  let register' = fromSortRec (subAlg (SortRec register))+  (register', ByteMem bytes)+  where+    acc :: [Byte] -> [Record] -> Int -> [Record]+    acc [] register _ = register+    acc ([] : remainingBytes) register i = acc remainingBytes register (i + 1)+    acc (byte : remainingBytes) register i = acc remainingBytes (register ++ [(i, last byte)]) (i + 1)++-- | Create a TensorStack with the collated and sorted References from the+--   Tensors as the Register and the original Tensors as the data++-- | ==== __Examples__+-- >>> getTensorFromTensors [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(1,14),(0,17)],ByteMem [[16,17],[12,14]])]+-- ([(1,17),(0,18)],TensorMem [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(1,14),(0,17)],ByteMem [[16,17],[12,14]])])+getTensorFromTensors :: [Tensor] -> SortAlg -> Tensor+getTensorFromTensors tensors subAlg = (fromSortRec (subAlg (SortRec (getRegisterFromTensors tensors))), TensorMem tensors)++-- | For each Tensor, produces a Record by combining the top bit of the+--  Tensor with an index value for its Address++-- | Note that this output is not sorted. Sorting is done in the+--   getTensorFromTensors function++-- | ==== __Examples__+-- >>> getRegisterFromTensors [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(0,14),(1,17)],ByteMem [[12,14],[16,17]]),([(0,3),(1,7)],ByteMem [[1,3],[5,7]]),([(0,4),(1,8)],ByteMem [[2,4],[6,8]])]+-- [(0,18),(1,17),(2,7),(3,8)]+getRegisterFromTensors :: [Tensor] -> [Record]+getRegisterFromTensors tensors = acc tensors []+  where+    acc :: [Tensor] -> [Record] -> [Record]+    acc [] records = records+    acc (([], _) : remainingTensors) records = acc remainingTensors records+    acc (tensor : remainingTensors) records = acc remainingTensors (records ++ [(i, getTopBitFromTensorStack tensor)])+      where+        i = length records++-- | Get the top Bit from a TensorStack++-- | The top Bit is the last Bit in the last Byte referenced in the last record+--   of the Tensor referenced in the last record of the last Tensor of...+--   and so on until you reach the top level of the TensorStack++-- | This is also expected to be the highest value in the TensorStack++-- | ==== __Examples__+-- >>> getTopBitFromTensorStack (([(0,28),(1,38)],TensorMem [([(0,27),(1,28)],TensorMem [([(0,23),(1,27)],ByteMem [[21,23],[25,27]]),([(0,24),(1,28)],ByteMem [[22,24],[26,28]])]),([(1,37),(0,38)],TensorMem [([(0,33),(1,38)],ByteMem [[31,33],[35,38]]),([(0,34),(1,37)],ByteMem [[32,14],[36,37]])])]))+-- 38+getTopBitFromTensorStack :: Tensor -> Bit+getTopBitFromTensorStack (register, _) = snd (last register)
src/Data/Tensort/Utils/Convert.hs view
@@ -1,7 +1,7 @@ module Data.Tensort.Utils.Convert (rawBitsToBytes) where  import Data.Tensort.Utils.Split (splitEvery)-import Data.Tensort.Utils.Types (Byte, Sortable (..), TensortProps (..), fromSortInt)+import Data.Tensort.Utils.Types (Byte, Sortable (..), TensortProps (..), fromSortBit, Bit)  -- | Convert a list of Bits to a list of Bytes of given bytesize, bubblesorting --   each byte.@@ -9,13 +9,13 @@ -- | ==== __Examples__ --   >>> rawBitsToBytes [5,1,3,7,8,2,4,6] 4 --   [[2,4,6,8],[1,3,5,7]]--- rawBitsToBytes :: [Int] -> Int -> [Byte]+-- rawBitsToBytes :: [Bit] -> Int -> [Byte] -- rawBitsToBytes bits bytesize = foldr acc [] (splitEvery bytesize bits) --   where---     acc :: [Int] -> [Byte] -> [Byte]---     acc byte bytes = bytes ++ [fromSortInt (bubblesort (SortInt byte))]-rawBitsToBytes :: [Int] -> TensortProps -> [Byte]+--     acc :: [Bit] -> [Byte] -> [Byte]+--     acc byte bytes = bytes ++ [fromSortBit (bubblesort (SortBit byte))]+rawBitsToBytes :: [Bit] -> TensortProps -> [Byte] rawBitsToBytes bits tsProps = foldr acc [] (splitEvery (bytesize tsProps) bits)   where-    acc :: [Int] -> [Byte] -> [Byte]-    acc byte bytes = bytes ++ [fromSortInt (subAlgorithm tsProps (SortInt byte))]+    acc :: [Bit] -> [Byte] -> [Byte]+    acc byte bytes = bytes ++ [fromSortBit (subAlgorithm tsProps (SortBit byte))]
src/Data/Tensort/Utils/RandomizeList.hs view
@@ -5,5 +5,5 @@ import System.Random.Shuffle (shuffle')  randomizeList :: Sortable -> Int -> Sortable-randomizeList (SortInt xs) seed = SortInt (shuffle' xs (length xs) (mkStdGen seed))+randomizeList (SortBit xs) seed = SortBit (shuffle' xs (length xs) (mkStdGen seed)) randomizeList (SortRec xs) seed = SortRec (shuffle' xs (length xs) (mkStdGen seed))
src/Data/Tensort/Utils/Reduce.hs view
@@ -1,8 +1,8 @@ module Data.Tensort.Utils.Reduce (reduceTensorStacks) where +import Data.Tensort.Utils.Compose (createTensor) import Data.Tensort.Utils.Split (splitEvery)-import Data.Tensort.Utils.Tensor (createTensorStack)-import Data.Tensort.Utils.Types (TensorStack, TensortProps (..))+import Data.Tensort.Utils.Types (Memory (..), TensorStack, TensortProps (..))  -- | Take a list of TensorStacks and group them together in new --   TensorStacks, each containing bytesize number of Tensors (former@@ -17,7 +17,7 @@ reduceTensorStacks tensorStacks tsProps = do   let newTensorStacks = reduceTensorStacksSinglePass tensorStacks tsProps   if length newTensorStacks <= bytesize tsProps-    then createTensorStack newTensorStacks (subAlgorithm tsProps)+    then createTensor (TensorMem newTensorStacks) (subAlgorithm tsProps)     else reduceTensorStacks newTensorStacks tsProps  -- | Take a list of TensorStacks  and group them together in new@@ -32,4 +32,4 @@ reduceTensorStacksSinglePass tensorStacks tsProps = foldr acc [] (splitEvery (bytesize tsProps) tensorStacks)   where     acc :: [TensorStack] -> [TensorStack] -> [TensorStack]-    acc tensorStack newTensorStacks = newTensorStacks ++ [createTensorStack tensorStack (subAlgorithm tsProps)]+    acc tensorStack newTensorStacks = newTensorStacks ++ [createTensor (TensorMem tensorStack) (subAlgorithm tsProps)]
src/Data/Tensort/Utils/Render.hs view
@@ -1,26 +1,26 @@-module Data.Tensort.Utils.Render (getSortedBitsFromMetastack) where+module Data.Tensort.Utils.Render (getSortedBitsFromTensor) where  import Data.Maybe (isNothing)-import Data.Tensort.Utils.Tensor (createTensor)-import Data.Tensort.Utils.Types (Memory (..), SortAlg, Sortable (..), Tensor, TensorStack, fromJust, fromSortInt)+import Data.Tensort.Utils.Compose (createTensor)+import Data.Tensort.Utils.Types (Memory (..), SortAlg, Sortable (..), Tensor, TensorStack, fromJust, fromSortBit, Bit)  -- | Compile a sorted list of Bits from a list of TensorStacks  -- | ==== __Examples__---  >>> getSortedBitsFromMetastack ([(0,5),(1,7)],ByteMem [[1,5],[3,7]])+--  >>> getSortedBitsFromTensor ([(0,5),(1,7)],ByteMem [[1,5],[3,7]]) --  [1,3,5,7]---  >>> getSortedBitsFromMetastack ([(0,8),(1,18)],TensorMem [([(0,7),(1,8)],TensorMem [([(0,3),(1,7)],ByteMem [[1,3],[5,7]]),([(0,4),(1,8)],ByteMem [[2,4],[6,8]])]),([(1,17),(0,18)],TensorMem [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(0,14),(1,17)],ByteMem [[12,14],[16,17]])])])+--  >>> getSortedBitsFromTensor ([(0,8),(1,18)],TensorMem [([(0,7),(1,8)],TensorMem [([(0,3),(1,7)],ByteMem [[1,3],[5,7]]),([(0,4),(1,8)],ByteMem [[2,4],[6,8]])]),([(1,17),(0,18)],TensorMem [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(0,14),(1,17)],ByteMem [[12,14],[16,17]])])]) --  [1,2,3,4,5,6,7,8,11,12,13,14,15,16,17,18]-getSortedBitsFromMetastack :: TensorStack -> SortAlg -> [Int]-getSortedBitsFromMetastack metastackRaw subAlg = acc metastackRaw []+getSortedBitsFromTensor :: TensorStack -> SortAlg -> [Bit]+getSortedBitsFromTensor tensorRaw subAlg = acc tensorRaw []   where-    acc :: TensorStack -> [Int] -> [Int]-    acc metastack sortedBits = do-      let (nextBit, metastack') = removeTopBitFromTensor metastack subAlg-      if isNothing metastack'+    acc :: TensorStack -> [Bit] -> [Bit]+    acc tensor sortedBits = do+      let (nextBit, tensor') = removeTopBitFromTensor tensor subAlg+      if isNothing tensor'         then nextBit : sortedBits         else do-          acc (fromJust metastack') (nextBit : sortedBits)+          acc (fromJust tensor') (nextBit : sortedBits)  -- | For use in compiling a list of Tensors into a sorted list of Bits --@@ -30,7 +30,7 @@ -- | ==== __Examples__ --   >>> removeTopBitFromTensor  ([(0,5),(1,7)],ByteMem [[1,5],[3,7]]) --   (7,Just ([(1,3),(0,5)],ByteMem [[1,5],[3]]))-removeTopBitFromTensor :: Tensor -> SortAlg -> (Int, Maybe Tensor)+removeTopBitFromTensor :: Tensor -> SortAlg -> (Bit, Maybe Tensor) removeTopBitFromTensor (register, memory) tsProps = do   let topRecord = last register   let topAddress = fst topRecord@@ -39,7 +39,7 @@     then (topBit, Nothing)     else (topBit, Just (createTensor (fromJust memory') tsProps)) -removeBitFromMemory :: Memory -> Int -> SortAlg -> (Int, Maybe Memory)+removeBitFromMemory :: Memory -> Int -> SortAlg -> (Bit, Maybe Memory) removeBitFromMemory (ByteMem bytes) i subAlg = do   let topByte = bytes !! i   let topBit = last topByte@@ -54,7 +54,7 @@       let bytes' = take i bytes ++ [topByte'] ++ drop (i + 1) bytes       (topBit, Just (ByteMem bytes'))     _ -> do-      let topByte'' = fromSortInt (subAlg (SortInt topByte'))+      let topByte'' = fromSortBit (subAlg (SortBit topByte'))       let bytes' = take i bytes ++ [topByte''] ++ drop (i + 1) bytes       (topBit, Just (ByteMem bytes')) removeBitFromMemory (TensorMem tensors) i subAlg = do
− src/Data/Tensort/Utils/Tensor.hs
@@ -1,101 +0,0 @@-module Data.Tensort.Utils.Tensor-  ( getTensorStacksFromBytes,-    createTensor,-    getTensorFromBytes,-    createTensorStack,-  )-where--import Data.Tensort.Utils.Split (splitEvery)-import Data.Tensort.Utils.Types (Byte, Memory (..), Record, SortAlg, Sortable (..), Tensor, TensorStack, TensortProps (..), fromSortRec)---- | Convert a list of Bytes to a list of TensorStacks.---- | This is accomplished by making a Tensor for each Byte, converting that---   Tensor into a TensorStack (these are equivalent terms - see type---   definitions for more info) and collating the TensorStacks into a list---- | ==== __Examples__---  >>> getTensorStacksFromBytes [[2,4],[6,8],[1,3],[5,7]] 2---  [([(0,3),(1,7)],ByteMem [[1,3],[5,7]]),([(0,4),(1,8)],ByteMem [[2,4],[6,8]])]-getTensorStacksFromBytes :: [Byte] -> TensortProps -> [TensorStack]-getTensorStacksFromBytes bytes tsProps = foldr acc [] (splitEvery (bytesize tsProps) bytes)-  where-    acc :: [Byte] -> [TensorStack] -> [TensorStack]-    acc byte tensorStacks = tensorStacks ++ [getTensorFromBytes byte (subAlgorithm tsProps)]---- | Create a Tensor from a Memory---   Aliases to getTensorFromBytes for ByteMem and createTensorStack for---   TensorMem---- | I expect to refactor to simplify this before initial release-createTensor :: Memory -> SortAlg -> Tensor-createTensor (ByteMem bytes) subAlg = getTensorFromBytes bytes subAlg-createTensor (TensorMem tensors) subAlg = createTensorStack tensors subAlg---- | Convert a list of Bytes to a Tensor---- | We do this by loading the list of Bytes into the new Tensor's Memory---   and adding a sorted Register containing References to each Byte in Memory---- | Each Record contains an Address pointing to the index of the referenced---   Byte and a TopBit containing the value of the last (i.e. highest) Bit in---   the referenced Byte---- | The Register is bubblesorted by the TopBits of each Record---- | ==== __Examples__---  >>> getTensorFromBytes [[2,4,6,8],[1,3,5,7]]---  ([(1,7),(0,8)],ByteMem [[2,4,6,8],[1,3,5,7]])-getTensorFromBytes :: [Byte] -> SortAlg -> Tensor-getTensorFromBytes bytes subAlg = do-  let register = acc bytes [] 0-  let register' = fromSortRec (subAlg (SortRec register))-  (register', ByteMem bytes)-  where-    acc :: [Byte] -> [Record] -> Int -> [Record]-    acc [] register _ = register-    acc ([] : remainingBytes) register i = acc remainingBytes register (i + 1)-    acc (byte : remainingBytes) register i = acc remainingBytes (register ++ [(i, last byte)]) (i + 1)---- | Create a TensorStack with the collated and bubblesorted References from the---   Tensors as the Register and the original Tensors as the data---- | ==== __Examples__--- >>> createTensorStack [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(1,14),(0,17)],ByteMem [[16,17],[12,14]])]--- ([(1,17),(0,18)],TensorMem [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(1,14),(0,17)],ByteMem [[16,17],[12,14]])])-createTensorStack :: [Tensor] -> SortAlg -> TensorStack-createTensorStack tensors subAlg = (fromSortRec (subAlg (SortRec (getRegisterFromTensors tensors))), TensorMem tensors)---- | For each Tensor, produces a Record by combining the top bit of the---  Tensor with an index value for its Address---- | Note that this output is not sorted. Sorting is done in the---   createTensorStack function---- | ==== __Examples__--- >>> getRegisterFromTensors [([(0,13),(1,18)],ByteMem [[11,13],[15,18]]),([(0,14),(1,17)],ByteMem [[12,14],[16,17]]),([(0,3),(1,7)],ByteMem [[1,3],[5,7]]),([(0,4),(1,8)],ByteMem [[2,4],[6,8]])]--- [(0,18),(1,17),(2,7),(3,8)]-getRegisterFromTensors :: [Tensor] -> [Record]-getRegisterFromTensors tensors = acc tensors []-  where-    acc :: [Tensor] -> [Record] -> [Record]-    acc [] records = records-    acc (([], _) : remainingTensors) records = acc remainingTensors records-    acc (tensor : remainingTensors) records = acc remainingTensors (records ++ [(i, getTopBitFromTensorStack tensor)])-      where-        i = length records---- | Get the top Bit from a TensorStack---- | The top Bit is the last Bit in the last Byte referenced in the last record---   of the Tensor referenced in the last record of the last Tensor of...---   and so on until you reach the top level of the TensorStack---- | This is also expected to be the highest value in the TensorStack---- | ==== __Examples__--- >>> getTopBitFromTensorStack (([(0,28),(1,38)],TensorMem [([(0,27),(1,28)],TensorMem [([(0,23),(1,27)],ByteMem [[21,23],[25,27]]),([(0,24),(1,28)],ByteMem [[22,24],[26,28]])]),([(1,37),(0,38)],TensorMem [([(0,33),(1,38)],ByteMem [[31,33],[35,38]]),([(0,34),(1,37)],ByteMem [[32,14],[36,37]])])]))--- 38-getTopBitFromTensorStack :: Tensor -> Int-getTopBitFromTensorStack (register, _) = snd (last register)
src/Data/Tensort/Utils/Types.hs view
@@ -8,13 +8,12 @@ --   defined here. Since these packages are only for sorting Ints currently, --   every data type is a structure of Ints ---   I know this might sound confusing, but in a recursive algorithm like this---   it's helpful to have different names for the same type of data depending---   on how it's being used, while still being able to use the same data in---   multiple contexts- -- | A Bit is a single element of the list to be sorted. For --   our current purposes that means it is an Int++-- | NOTE: To Self: at this point it's likely simple enough to refactor this+--   to sort any Ord, not just Ints. Consider using the `Bit` type synonym+--   in the code, then changing this to alias `Bit` to `Ord` or `a` type Bit = Int  -- | A Byte is a list of Bits standardized to a fixed maximum length (Bytesize)@@ -30,36 +29,36 @@ --   Tensor type TopBit = Bit --- | A Record is an element in a Tensor or Metatensor's Register+-- | A Record is an element in a Tensor's Register --   containing an Address pointer and a TopBit value  -- | A Record's Address is an index number pointing to a Byte or Tensor in---   the Tensor/Metatensor's Memory+--   the Tensor's Memory  -- | A Record's TopBit is a copy of the last (i.e. highest) Bit in the Byte or --   Tensor that the Record references type Record = (Address, TopBit)  -- | A Register is a list of Records allowing for easy access to data in a---   Tensor or Metatensor's Memory+--   Tensor's Memory type Register = [Record] --- | We use a Sortable type sort between Ints and Records+-- | We use a Sortable type sort between Bits and Records  -- | In the future this may be expanded to include other data types and allow---   for sorting other types of besides Ints+--   for sorting other types of besides Ints. data Sortable-  = SortInt [Int]+  = SortBit [Bit]   | SortRec [Record]   deriving (Show, Eq, Ord) -fromSortInt :: Sortable -> [Int]-fromSortInt (SortInt ints) = ints-fromSortInt (SortRec _) = error "This is for sorting Integers - you gave me Records"+fromSortBit :: Sortable -> [Bit]+fromSortBit (SortBit bits) = bits+fromSortBit (SortRec _) = error "This is for sorting Bits - you gave me Records"  fromSortRec :: Sortable -> [Record] fromSortRec (SortRec recs) = recs-fromSortRec (SortInt _) = error "This is for sorting Records - you gave me Integers"+fromSortRec (SortBit _) = error "This is for sorting Records - you gave me Bits"  type SortAlg = Sortable -> Sortable @@ -68,22 +67,29 @@ type SupersortStrat = (Sortable, Sortable, Sortable) -> Sortable  -- | A Memory contains the data to be sorted, either in the form of Bytes or---   Tensors+--   Tensors.++-- | Technically the Memory is a tensor field, but it seems +--   less confusing to just call it Memory data Memory   = ByteMem [Byte]   | TensorMem [Tensor]   deriving (Show, Eq, Ord) --- | A Tensor is a Metatensor that only contains Bytes in its memory--- | The Memory is a list of the Bytes or Tensors that the Tensor---   contains.+-- | A Tensor contains data to be sorted in a structure allowing for+--   easy access. It consists of a Register and its Memory. --- | The Register is a list of Records referencing the top Bits in Memory+-- | The Memory is a list of the Bytes or other Tensors that this Tensor+--   contains. Technically the Memory is a tensor field, but it seems +--   less confusing to just call it Memory.++-- | The Register is a list of Records referencing the top Bits in Memory.+ type Tensor = (Register, Memory)  -- | A TensorStack is a top-level Tensor. In the final stages of Tensort, the --   number of TensorStacks will equal the bytesize, but before that time there---   are expected to be many more TensorStacks+--   are expected to be many more TensorStacks. type TensorStack = Tensor  fromJust :: Maybe a -> a
tensort.cabal view
@@ -20,14 +20,41 @@ -- PVP summary:     +-+------- breaking API changes --                  | | +----- non-breaking API additions --                  | | | +--- code changes with no API change-version:            0.1.0.0+version:            0.2.0.0 +tested-with:        GHC==9.8.2, +                    GHC==9.6.4, +                    GHC==9.4.8,+                    GHC==9.2.8,+                    GHC==9.2.1,+                    GHC==9.0.2,+                    GHC==8.10.7,+                    GHC==8.8.4,+                    GHC==8.6.5,+                    GHC==8.4.4,+                    GHC==8.2.2,+                    GHC==8.0.2,+                    GHC==7.10.3,+                    GHC==7.6.3,+                    GHC==7.4.2,+                    GHC==7.0.4,+                    GHC==7.0.1,+ -- A short (one-line) description of the package.-synopsis:           Reasonably robust sorting in O(n log n) time+synopsis:           Tunable sorting for responsive robustness and beyond!  -- A longer description of the package.-description:        An exploration of robustness in algorithms for sorting integers, inspired by [Beyond Efficiency](https://www.cs.unm.edu/~ackley/be-201301131528.pdf) by David H. Ackley+description:        A tunable tensor-based structure for sorting algorithms +                    along with various sample configurations. Birthed from an +                    exploration of robustness in algorithms for sorting +                    integers, inspired by +                    [Beyond Efficiency](https://www.cs.unm.edu/~ackley/be-201301131528.pdf) +                    by David H. Ackley and +                    [Beyond Efficiency by Dave Ackley](https://futureofcoding.org/episodes/070) +                    by Future of Coding. +homepage: https://github.com/kaBeech/tensort+ -- The license under which the package is released. license:            MIT @@ -49,11 +76,16 @@ build-type:         Simple  -- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.-extra-doc-files:    CHANGELOG.md+extra-doc-files:    README.md,+                    CHANGELOG.md  -- Extra source files to be distributed with the package, such as examples, or a tutorial module. -- extra-source-files: +source-repository head+    type:           git+    location:       https://github.com/kaBeech/tensort+ common warnings     ghc-options: -Wall @@ -67,7 +99,7 @@                       Data.Tensort.Robustsort,                       Data.Tensort.Utils.Types,                       Data.Tensort.Subalgorithms.Bubblesort,-                      Data.Tensort.Subalgorithms.ReverseExchangesort,+                      Data.Tensort.Subalgorithms.Exchangesort,                       Data.Tensort.Subalgorithms.Permutationsort,                       Data.Tensort.Subalgorithms.Bogosort,                       Data.Tensort.Subalgorithms.Supersort,@@ -75,13 +107,13 @@                       Data.Tensort.OtherSorts.Mergesort,                       Data.Tensort.OtherSorts.Quicksort,                       Data.Tensort.Utils.RandomizeList,+                      Data.Tensort.Utils.Check,      -- Modules included in this library but not exported.-    other-modules:    Data.Tensort.Utils.Check,-                      Data.Tensort.Utils.Split,+    other-modules:    Data.Tensort.Utils.Split,                       Data.Tensort.Utils.ComparisonFunctions,                       Data.Tensort.Utils.Convert,-                      Data.Tensort.Utils.Tensor,+                      Data.Tensort.Utils.Compose,                       Data.Tensort.Utils.Reduce,                       Data.Tensort.Utils.Render, @@ -89,9 +121,9 @@     -- other-extensions:      -- Other library packages from which modules are imported.-    build-depends:    base ^>=4.18.2.0,-                      mtl >= 2.3.1 && < 2.4,-                      random >= 1.2.1 && < 1.3,+    build-depends:    base >=4.3.0.0 && <= 4.19.1.0,+                      mtl >= 2.2.2  && < 2.4,+                      random >= 1.0.0.3 && < 1.3,                       random-shuffle >= 0.0.4 && < 0.1,      -- Directories containing source files.@@ -115,9 +147,9 @@      -- Other library packages from which modules are imported.     build-depends:-        base ^>=4.18.2.0,+        base,         tensort,-        time >= 1.12.2 && < 1.13,+        time >= 1.2.0.3 && < 1.13,      -- Directories containing source files.     hs-source-dirs:   app@@ -133,7 +165,9 @@     default-language: Haskell2010      -- Modules included in this executable, other than Main.-    -- other-modules:+    other-modules:    TestCheck,+                      SortSpec,+                            -- LANGUAGE extensions used by modules in this package.     -- other-extensions:@@ -149,5 +183,7 @@      -- Test dependencies.     build-depends:-        base ^>=4.18.2.0,-        tensort+        base,+        tensort,+        mtl,+        QuickCheck >= 2.15 && < 2.16,
test/Main.hs view
@@ -1,4 +1,68 @@ module Main (main) where +import Data.Tensort.OtherSorts.Mergesort (mergesort)+import Data.Tensort.OtherSorts.Quicksort (quicksort)+import Data.Tensort.Robustsort (robustsortB, robustsortM, robustsortP)+import Data.Tensort.Subalgorithms.Bogosort (bogosort)+import Data.Tensort.Subalgorithms.Bubblesort (bubblesort)+import Data.Tensort.Subalgorithms.Exchangesort (exchangesort)+import Data.Tensort.Subalgorithms.Magicsort (magicsort)+import Data.Tensort.Subalgorithms.Permutationsort (permutationsort)+import Data.Tensort.Subalgorithms.Supersort (magicSuperStrat, mundaneSuperStrat, supersort)+import Data.Tensort.Tensort (mkTSProps, tensort, tensortB4, tensortBL, tensortBN)+import Data.Tensort.Utils.Types (Sortable (..))+import SortSpec (result_is_sorted_bits, result_is_sorted_records, result_is_sorted_records_short)+import TestCheck (check)++-- | This suite of QuickCheck tests contains  a guard that will cause the test+--   `suite to fail if any of the individual tests fail main :: IO ()-main = putStrLn "Test suite not yet implemented."+main = do+  putStrLn "Running test suite!"+  putStrLn "Quicksort returns a sorted array..."+  check (result_is_sorted_records quicksort)+  putStrLn "True!"+  putStrLn "Mergesort returns a sorted array..."+  check (result_is_sorted_records mergesort)+  putStrLn "True!"+  putStrLn "Bubblesort returns a sorted array..."+  check (result_is_sorted_records bubblesort)+  putStrLn "True!"+  putStrLn "Exchangesort returns a sorted array..."+  check (result_is_sorted_records exchangesort)+  putStrLn "True!"+  putStrLn "Permutationsort returns a sorted array..."+  check (result_is_sorted_records permutationsort)+  putStrLn "True!"+  putStrLn "Bogosort returns a sorted array..."+  check (result_is_sorted_records bogosort)+  putStrLn "True!"+  putStrLn "Magicsort returns a sorted array..."+  -- check (result_is_sorted_records_short magicsort)+  let magicRes = magicsort (SortBit [5, 2, 3, 1, 4])+  print magicRes+  check (magicRes == SortBit [1, 2, 3, 4, 5])+  putStrLn "True!"+  putStrLn "Standard Logaritmic Tensort returns a sorted array..."+  let logRes = tensortBL [5, 2, 3, 1, 4]+  print logRes+  check (logRes == [1, 2, 3, 4, 5])+  -- check (result_is_sorted_bits tensortBL)+  putStrLn "True!"+  putStrLn "Standard 4-Bit Tensort returns a sorted array..."+  check (result_is_sorted_bits tensortB4)+  putStrLn "True!"+  -- TBA+  putStrLn "Standard Mundane Robustsort with Permutationsort adjudicator returns a sorted array..."+  check (result_is_sorted_bits robustsortP)+  putStrLn "True!"+  putStrLn "Standard Mundane Robustsort with Bogosort adjudicator returns a sorted array..."+  check (result_is_sorted_bits robustsortB)+  putStrLn "True!"+  putStrLn "Magic Robustsort returns a sorted array..."+  let magicRoboRes = magicsort (SortBit [5, 2, 3, 1, 4])+  print magicRoboRes+  check (magicRoboRes == SortBit [1, 2, 3, 4, 5])+  -- check (result_is_sorted_bits robustsortM)+  putStrLn "True!"+  putStrLn "All tests pass!"
+ test/SortSpec.hs view
@@ -0,0 +1,18 @@+module SortSpec (result_is_sorted_bits, result_is_sorted_records, result_is_sorted_records_short) where++import Data.Tensort.Utils.Check (isSorted)+import Data.Tensort.Utils.Types (Bit, Record, SortAlg, Sortable (..))+import Test.QuickCheck++result_is_sorted_bits :: ([Bit] -> [Bit]) -> [Bit] -> Property+result_is_sorted_bits sort unsortedList = (length unsortedList < 10) && not (null unsortedList) ==> isSorted (SortBit (sort unsortedList))++result_is_sorted_records :: SortAlg -> [Record] -> Property+result_is_sorted_records sort unsortedList = (length unsortedList < 10) && not (null unsortedList) ==> isSorted (sort (SortRec unsortedList))++result_is_sorted_records_short :: SortAlg -> [Record] -> Property+result_is_sorted_records_short sort unsortedList = (length unsortedList < 6) && not (null unsortedList) ==> isSorted (sort (SortRec unsortedList))++result_is_sorted_sortable :: SortAlg -> Sortable -> Property+result_is_sorted_sortable sort (SortBit unsortedList) = (length unsortedList < 10) && not (null unsortedList) ==> isSorted (sort (SortBit unsortedList))+result_is_sorted_sortable sort (SortRec unsortedList) = (length unsortedList < 10) && not (null unsortedList) ==> isSorted (sort (SortRec unsortedList))
+ test/TestCheck.hs view
@@ -0,0 +1,36 @@+module TestCheck (isPass, check) where++import Control.Monad (unless)+import System.Exit+import Test.QuickCheck++-- | Run a QuickCheck test and exit with a failure if it fails++-- | This is used so that the testing suite will fail if any QuickCheck tests+--   fail++-- | ==== __Examples__+--   >>> check (1 == 1)+--   ...+--   >>> check (1 == 2)+--   ...+--   ...exit with failure+check :: (Testable prop) => prop -> IO ()+check prop = do+  result <- quickCheckResult prop+  unless (isPass result) exitFailure++-- | Returns True if a test passes, and False otherwise++-- | ==== __Examples__+--   >>> isPass (Success {})+--   True+--   >>> isPass (GaveUp {})+--   False+--   >>> isPass (Failure {})+--   False+--   >>> isPass (_ {})+--   False+isPass :: Result -> Bool+isPass (Success {}) = True+isPass _ = False