Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
fenilgmehta committed Aug 11, 2019
2 parents d5ca640 + 544b340 commit 45a0995
Show file tree
Hide file tree
Showing 65 changed files with 791 additions and 157,119 deletions.
127 changes: 76 additions & 51 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,73 +1,103 @@
# Fastest-Integer-Sort
These are generalised functions written in C++ which are highly optimised for the sorting of integer based array or vectors. It is 2.48 times faster than C++ STL std::sort for "std::vector<uint64_t> arrayName(10000000)".
Algorithm written in C++ which is highly optimised for the sorting of arrays and vectors of large objects.


Details
Graph
----------------------------------
1. "ir_sort::integer_sort" is the name of the function to sort the integer based arrays.
2. Four parameters: first two parameters are same as std::sort, ascendingOrder(boolean)(optional), forceLinearSort(integer)(optional)
3. Sort the input in ascending order and descending order.
4. Compiled using "g++ -std=c++14 -O2 -m64 -march=native" for testing
5. Can be called on all containers with RandomAccessIterator
6. Requirements:
* [first, last) is a valid range.
* RandomAccessIterator value_type is mutable.
* RandomAccessIterator value_type is LessThanComparable.
* RandomAccessIterator value_type supports the operator>>, which returns an integer-type right-shifted a specified number of bits.
* RandomAccessIterator supports the operator[], which returns the i'th element of the container.
![Running time comparision of fm_sort optimization with other sorting algorithms](https://raw.githubusercontent.com/fenilgmehta/Fastest-Integer-Sort/develop/graphs_and_analysis/Graphs_v3/Figure_1.png)


Features
Stats
----------------------------------
1. faster than any other sorting algorithm for integer arrays
2. stable sorting
3. takes the advantage of binary operations over decimal operations
4. linear time complexity
5. very useful in competitions(refer "ir_sort_competitions.cpp" for usage in competitions)
6. added new function for sorting object arrays based on integer keys
7. valid but not limited to the following C++ Standard Template Library(STL) containers for sorting:
* std::array
* std::valarray
* std::vector
* std::deque

* Results for ```Array length = 781250```, ```Object size = 4 K bytes = vector<uint64_t>[512]```, ```Array size = 2.98 GB```:
- 6.32 times faster than C++ STL std::sort
- 5.55 times faster than std::stable_sort
- 3.80 times faster than pdqsort
- 3.15 times faster than spinsort
- 2.82 times faster than timsort
- 2.55 times faster than flat_stable_sort
- 2.22 times faster than spreadsort
- 1.53 times faster than skasort

* Test conditions:
1. Compiled using "g++ -std=c++17 -O2 -m64 -march=native" for testing
2. timsort is used to sort the array/vector of objects based on index
3. Arrays used to test the performance
- random
- sorted
- sorted + 0.1% end
- sorted + 1% end
- sorted + 10% end
- sorted + 0.1% mid
- sorted + 1% mid
- sorted + 10% mid
- rev sorted
- rev sorted + 0.1% end
- rev sorted + 1% end
- rev sorted + 10% end
- rev sorted + 0.1% mid
- rev sorted + 1% mid
- rev sorted + 10% mid

Time complexity
Details
----------------------------------
| Case | Time complexity |
|:------------:|:---------------:|
| best case | Ω(nk) |
| average case | θ(nk) |
| worst case | O(nk) |

1. "fm_sort::fm_sort_objects" is the name of the function to sort an array based on index
2. Three parameters:
- first : iterator pointing to the first element of the object array
- last : iterator pointing the element one beyond the last element
- p_arr_index: Auxiliary array/vector with the correct index of the elements of the range [first, last)
3. Sort the input in ascending order and descending order.
4. Can be called on all containers with RandomAccessIterator
5. Time complexity depends on the sorting algorithm used to sort the index array
6. Auxiliary space complexity is O(n) - a vector of type uint16_t/uint32_t/uint64_t of size **n** is required which can be negligible as compared to the size of the array/vector to be sorted and the performance improvement.

Graph
Features
----------------------------------
![Speed Comparison, int64_t](https://raw.githubusercontent.com/fenilgmehta/Fastest-Integer-Sort/master/graphs_and_analysis/all_comparisons/rawData_int64_t/Figure_1_int64_t.png)
![Speed Comparison, int32_t](https://raw.githubusercontent.com/fenilgmehta/Fastest-Integer-Sort/master/graphs_and_analysis/all_comparisons/rawData_int32_t/Figure_1_int32_t.png)
![Speed Comparison, int16_t](https://raw.githubusercontent.com/fenilgmehta/Fastest-Integer-Sort/master/graphs_and_analysis/all_comparisons/rawData_int16_t/Figure_1_int16_t.png)
![Speed Comparison, int8_t](https://raw.githubusercontent.com/fenilgmehta/Fastest-Integer-Sort/master/graphs_and_analysis/all_comparisons/rawData_int8_t/Figure_1_int8_t.png)
1. faster than any other sorting algorithm for large object arrays
2. stable/unstable sorting based on the sorting technique used to sort the index array
3. takes the advantage of large size of the objects
4. very useful in places where in-memory sorting is to be performed on large objects
5. valid but not limited to the following C++ Standard Template Library(STL) containers for sorting:
* std::vector
* std::array
* std::valarray


Basic working
----------------------------------
It is a stable sorting algorithm.
This algorithm takes the advantage of bitwise operations provided by the C++ language on top of processors which run at a very high speed as compared to the other operations like addition, subtraction, multiplication, division, etc. Along with this, it uses radix sort to make the sorting faster.
I have combined the above mentioned things into one algorithm which would sort the input given to it. To improve the performance for small size of input arrays, I have used insertion sort and merge sort.
The graphs above shows how ir_sort::integer_sort starts performing better with higher array size.
* Working of swapping optimization
- Once fm_sort get the correct positions of the objects in the index array, the original array is sorted based on the index array in just **n** swaps
* Working of the ir_sort
- This algorithm takes the advantage of bitwise operations provided by the C++ language on top of processors which run at a very high speed as compared to the other operations like addition, subtraction, multiplication, division, etc. Along with this, it uses radix sort to make the sorting faster.
- I have combined the above mentioned things into one algorithm which would sort the input given to it.


Usage
----------------------------------
For projects:
* To use this sorting optimization in your project, follow the below mentioned steps -
```c++
// copy the following four files to the project folder: "basic_sorts.hpp", "ir_commons.hpp", "integer_sort.cpp" and "integer_sort_objects_small.cpp"
// copy the following four files to the project folder: "ir_commons.hpp", "integer_sort.hpp" and "integer_sort_objects_small.hpp"

// paste the following lines in the file start
include "integer_sort.cpp"
#include "integer_sort.hpp"
#include "integer_sort_objects_small.hpp"

// assume "arr1" is the vector of objects(type T) to be sorted
// assume "compare_function" is a function which is used to compare elements(type T) of the vector "arr1"

using IndexType = uint64_t;
vector<IndexType> p_arr_index(arr1.size());
iota(p_arr_index.begin(), p_arr_index.end(), 0);

auto arr_first = arr1.begin();
std::sort(p_arr_index.begin(), p_arr_index.end(), [arr_first](const IndexType &a, const IndexType &b) { return compare_function(arr_first[a], arr_first[b]); });

fm_sort::fm_sort_objects(arr1.begin(), arr1.end(), begin(p_arr_index));

```
For competitions:
* To use the radix sort in competitions, follow the below mentioned steps:
```c++
// copy the namespace "ir_sort" from "ir_sort_competitions.cpp" to the main ".cpp" program file
Expand All @@ -80,8 +110,3 @@ ir_sort::integer_sort(begin, end)
```


TODO
----------------------------------
1. Write the sorting function to sort the array of objects based on integer key without creating copy of the objects.
* descending order for +ve and -ve numbers
* this will be useful where the objects are large in size.
Binary file added graphs_and_analysis/Graphs_v1.zip
Binary file not shown.
Binary file added graphs_and_analysis/Graphs_v2.zip
Binary file not shown.
Binary file added graphs_and_analysis/Graphs_v3/Figure_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
35 changes: 35 additions & 0 deletions graphs_and_analysis/Graphs_v3/data_extractor_v3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
arr = [input().split("|") for i in range(15)]

import re
res = []
for i in arr:
res.append([])
res[-1].append(i[0].strip())
for j in range(1, len(i)):
res[-1].extend(re.split(r"\s",i[j].strip()))

print(" |", end="")
for i in range(1, 10):
print(f" {i} ", end="|")

print()
print(" |", end="")
for i in range(1, 10):
print(f" H L ", end="|")

print()
for i in res:
print(f"{i[0]:24}", end=",")
for j in range(1, len(i)):
if i[j] != "": print(f"{i[j]:6}", end=",")
print()


########################################################################################
### EXCEL formula ###

# =SUM(B26:B40)
# =SUM(C26:C40)

# =MIN(B42,D42,F42,H42,J42,L42,N42,P42,R42)
# =MIN(C42,E42,G42,I42,K42,M42,O42,Q42,S42)
63 changes: 63 additions & 0 deletions graphs_and_analysis/Graphs_v3/graph_plotter_v3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns

# INPUT
names = np.array(["std::sort", "pdqsort", "std::stable_sort", "spinsort", "flat_stable_sort", "spreadsort", "timsort", "skasort", "fm_sort\noptimization"])[::-1]
Averages = [174.19, 30.06, 104.68, 20.04, 152.71, 151.56, 86.94, 59.96, 70.32, 50.75, 61.38, 17.42, 77.88, 67.69, 42.41, 27.85, 27.55, 10.08][::-1]
range_limit = 1000
graph_title = 'Array size = 2.98 GB\nArray length = 781250\nObject size = 4 K bytes = vector<uint64_t>[512]'
y_label_name = f'Running time - normalized to range[0, {range_limit}]'

names2 = []
for i in names:
names2.append(i)
names2.append(i)

v1 = np.array(Averages[::2])
v2 = np.array(Averages[1::2])
v1 = v1 * range_limit / v1.max()
v2 = v2 * range_limit / v2.max()

p1 = pd.DataFrame([names, v1]).T
p2 = pd.DataFrame([names, v2]).T
p3 = pd.DataFrame([names2, Averages, len(names)*["Light comparison","Heavy comparison"]], index=["Sorting technique", "Average execution time" ,"Data comparision type"]).T
p3["Average execution time"] = p3["Average execution time"] * range_limit / p3["Average execution time"].max()

# GRAPH type 1
x_pos = range(len(names))
plt.bar(x_pos, v1)
plt.xticks(x_pos, names)
plt.yticks(range(0, range_limit+1, range_limit//10), [str(i) for i in range(0, range_limit+1, range_limit//10)])
plt.ylabel(y_label_name)
plt.title(graph_title)
plt.show()

# GRAPH type 2
sns.set(style="whitegrid")
ax = sns.barplot(x="Sorting technique", y="Average execution time", hue="Data comparision type", data=p3, palette=sns.color_palette("coolwarm", 17)[0::16] )
# ax.axhline(0, color="k", clip_on=False)

for p in ax.patches:
ax.annotate(f"{p.get_height():.0f}", (p.get_x() * 1.005, p.get_height() * 1.005))

# for ticks in ax.xaxis.get_major_ticks():
# if ticks.label1.get_text() == names[-1]:
# # ticks.label1.set_facecolor("red")
# # ax.patches[p3.index.get_indexer([ticks.label1.get_text()])[0]].set_facecolor('red')
# ax.patches[p3.index.get_indexer([ticks.label1.get_text()])[0]].set_facecolor('red')

plt.yticks(range(0, range_limit+1, range_limit//10), [str(i) for i in range(0, range_limit + 1, range_limit//10)])
plt.ylabel(y_label_name)
plt.title(graph_title)
plt.tight_layout(h_pad=2)
plt.show()


# REFER: https://seaborn.pydata.org/tutorial/color_palettes.html
# REFER: https://seaborn.pydata.org/examples/color_palettes.html
# default_color_palette = sns.color_palette()
# cool_warm_tuple = sns.color_palette("coolwarm", 17)
# sns.palplot(cool_warm_tuple)
# plt.show()
82 changes: 82 additions & 0 deletions graphs_and_analysis/Graphs_v3/time_comparision_128_1562500.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@

************************************************************
** **
** B O O S T S O R T **
** **
** O B J E C T S B E N C H M A R K **
** **
************************************************************

=============================================================
= OBJECT COMPARISON =
= --------------------- =
= =
= The objects are arrays of 64 bits numbers =
= They are compared in two ways : =
= (H) Heavy : The comparison is the sum of all the numbers =
= of the array =
= (L) Light : The comparison is with the first element of =
= the array, as a key =
= =
============================================================


************************************************************
** **
1562500 OBJECTS UINT64_T [128]
** **
************************************************************

[ 1 ] std::sort [ 2 ] pdqsort [ 3 ] std::stable_sort
[ 4 ] spinsort [ 5 ] flat_stable_sort [ 6 ] spreadsort
[ 7 ] timsort [ 8 ] skasort [ 9 ] timsort with swapping optimization

| [ 1 ] | [ 2 ] | [ 3 ] | [ 4 ] | [ 5 ] | [ 6 ] | [ 7 ] | [ 8 ] | [ 9 ] |
| H L | H L | H L | H L | H L | H L | H L | H L | H L |
--------------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
random | 4.93 2.10| 2.55 0.83| 5.50 5.17| 2.96 1.98| 2.81 1.62| 1.93 0.52| 4.48 3.27| 1.63 1.20| 2.64 0.66|
| | | | | | | | | |
sorted | 5.15 1.52| 0.55 0.03| 5.28 5.01| 0.18 0.01| 0.18 0.01| 0.18 0.01| 0.20 0.01| 1.29 0.96| 0.19 0.02|
sorted + 0.1% end | 6.08 1.50| 0.92 0.05| 5.30 5.05| 1.06 0.70| 0.24 0.03| 1.04 0.18| 0.23 0.02| 1.31 0.95| 0.22 0.03|
sorted + 1% end | 5.70 1.69| 0.88 0.05| 5.39 5.16| 1.11 0.69| 0.24 0.03| 0.91 0.17| 0.24 0.02| 1.29 0.96| 0.25 0.04|
sorted + 10% end | 5.95 1.83| 0.70 0.05| 5.76 5.44| 1.40 0.93| 0.33 0.09| 1.02 0.19| 0.33 0.06| 1.42 1.07| 0.31 0.07|
| | | | | | | | | |
sorted + 0.1% mid | 7.24 2.78| 2.47 0.03| 5.36 4.97| 2.54 0.01| 0.85 0.01| 1.73 0.01| 0.57 0.01| 1.28 0.55| 0.32 0.02|
sorted + 1% mid | 6.31 2.80| 2.45 0.03| 5.43 5.06| 2.58 0.01| 1.13 0.01| 1.71 0.01| 0.61 0.01| 1.30 0.56| 0.36 0.02|
sorted + 10% mid | 5.56 3.06| 2.47 0.03| 5.85 5.49| 2.91 0.01| 1.30 0.01| 1.41 0.02| 1.08 0.01| 1.56 0.61| 0.76 0.02|
| | | | | | | | | |
reverse sorted | 4.29 1.64| 0.60 0.24| 5.37 5.11| 1.61 1.23| 1.39 0.92| 1.56 0.49| 1.04 0.82| 1.47 1.16| 0.54 0.36|
rv sorted + 0.1% end| 7.02 2.55| 2.17 0.41| 5.33 5.12| 1.57 1.24| 1.12 0.71| 1.51 0.49| 1.03 0.82| 1.46 1.17| 0.56 0.37|
rv sorted + 1% end| 5.98 2.28| 2.20 0.42| 5.40 5.25| 1.60 1.29| 1.14 0.73| 1.51 0.49| 1.05 0.84| 1.49 1.22| 0.59 0.38|
rv sorted + 10% end| 5.58 2.26| 2.21 0.46| 5.84 5.62| 1.89 1.44| 1.33 0.76| 1.55 0.51| 1.12 0.84| 1.64 1.30| 0.64 0.41|
| | | | | | | | | |
rv sorted + 0.1% mid| 7.31 2.74| 1.00 0.03| 5.40 4.97| 3.55 0.01| 1.46 0.01| 1.51 0.01| 2.46 0.01| 1.46 0.55| 0.60 0.02|
rv sorted + 1% mid| 6.40 2.75| 0.99 0.03| 5.46 5.01| 3.61 0.01| 2.37 0.01| 1.54 0.01| 2.53 0.01| 1.49 0.56| 0.65 0.02|
rv sorted + 10% mid| 5.80 3.04| 1.04 0.03| 6.04 5.60| 3.97 0.01| 2.50 0.02| 1.65 0.02| 3.20 0.01| 1.64 0.62| 1.16 0.02|
--------------------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+



| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
| H L | H L | H L | H L | H L | H L | H L | H L | H L |
random ,4.93 ,2.10 ,2.55 ,0.83 ,5.50 ,5.17 ,2.96 ,1.98 ,2.81 ,1.62 ,1.93 ,0.52 ,4.48 ,3.27 ,1.63 ,1.20 ,2.64 ,0.66 ,
sorted ,5.15 ,1.52 ,0.55 ,0.03 ,5.28 ,5.01 ,0.18 ,0.01 ,0.18 ,0.01 ,0.18 ,0.01 ,0.20 ,0.01 ,1.29 ,0.96 ,0.19 ,0.02 ,
sorted + 0.1% end ,6.08 ,1.50 ,0.92 ,0.05 ,5.30 ,5.05 ,1.06 ,0.70 ,0.24 ,0.03 ,1.04 ,0.18 ,0.23 ,0.02 ,1.31 ,0.95 ,0.22 ,0.03 ,
sorted + 1% end ,5.70 ,1.69 ,0.88 ,0.05 ,5.39 ,5.16 ,1.11 ,0.69 ,0.24 ,0.03 ,0.91 ,0.17 ,0.24 ,0.02 ,1.29 ,0.96 ,0.25 ,0.04 ,
sorted + 10% end ,5.95 ,1.83 ,0.70 ,0.05 ,5.76 ,5.44 ,1.40 ,0.93 ,0.33 ,0.09 ,1.02 ,0.19 ,0.33 ,0.06 ,1.42 ,1.07 ,0.31 ,0.07 ,
sorted + 0.1% mid ,7.24 ,2.78 ,2.47 ,0.03 ,5.36 ,4.97 ,2.54 ,0.01 ,0.85 ,0.01 ,1.73 ,0.01 ,0.57 ,0.01 ,1.28 ,0.55 ,0.32 ,0.02 ,
sorted + 1% mid ,6.31 ,2.80 ,2.45 ,0.03 ,5.43 ,5.06 ,2.58 ,0.01 ,1.13 ,0.01 ,1.71 ,0.01 ,0.61 ,0.01 ,1.30 ,0.56 ,0.36 ,0.02 ,
sorted + 10% mid ,5.56 ,3.06 ,2.47 ,0.03 ,5.85 ,5.49 ,2.91 ,0.01 ,1.30 ,0.01 ,1.41 ,0.02 ,1.08 ,0.01 ,1.56 ,0.61 ,0.76 ,0.02 ,
reverse sorted ,4.29 ,1.64 ,0.60 ,0.24 ,5.37 ,5.11 ,1.61 ,1.23 ,1.39 ,0.92 ,1.56 ,0.49 ,1.04 ,0.82 ,1.47 ,1.16 ,0.54 ,0.36 ,
rv sorted + 0.1% end ,7.02 ,2.55 ,2.17 ,0.41 ,5.33 ,5.12 ,1.57 ,1.24 ,1.12 ,0.71 ,1.51 ,0.49 ,1.03 ,0.82 ,1.46 ,1.17 ,0.56 ,0.37 ,
rv sorted + 1% end ,5.98 ,2.28 ,2.20 ,0.42 ,5.40 ,5.25 ,1.60 ,1.29 ,1.14 ,0.73 ,1.51 ,0.49 ,1.05 ,0.84 ,1.49 ,1.22 ,0.59 ,0.38 ,
rv sorted + 10% end ,5.58 ,2.26 ,2.21 ,0.46 ,5.84 ,5.62 ,1.89 ,1.44 ,1.33 ,0.76 ,1.55 ,0.51 ,1.12 ,0.84 ,1.64 ,1.30 ,0.64 ,0.41 ,
rv sorted + 0.1% mid ,7.31 ,2.74 ,1.00 ,0.03 ,5.40 ,4.97 ,3.55 ,0.01 ,1.46 ,0.01 ,1.51 ,0.01 ,2.46 ,0.01 ,1.46 ,0.55 ,0.60 ,0.02 ,
rv sorted + 1% mid ,6.40 ,2.75 ,0.99 ,0.03 ,5.46 ,5.01 ,3.61 ,0.01 ,2.37 ,0.01 ,1.54 ,0.01 ,2.53 ,0.01 ,1.49 ,0.56 ,0.65 ,0.02 ,
rv sorted + 10% mid ,5.80 ,3.04 ,1.04 ,0.03 ,6.04 ,5.60 ,3.97 ,0.01 ,2.50 ,0.02 ,1.65 ,0.02 ,3.20 ,0.01 ,1.64 ,0.62 ,1.16 ,0.02 ,

Averages = [89.3, 34.54, 23.2, 2.72, 82.71, 78.03, 32.54, 9.57, 18.39, 4.97, 20.76, 3.13, 20.17, 6.76, 21.73, 13.44, 9.79, 2.46]
Best = [9.79, 2.46]

Array length = 1562500
OBJECTS UINT64_T [128]
Loading

0 comments on commit 45a0995

Please sign in to comment.