Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Odd-Even Transposition Sort #769

Merged
merged 2 commits into from
Jun 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions sorts/Odd-Even_transposition_parallel.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
"""
This is an implementation of odd-even transposition sort.

It works by performing a series of parallel swaps between odd and even pairs of
variables in the list.

This implementation represents each variable in the list with a process and
each process communicates with its neighboring processes in the list to perform
comparisons.
They are synchronized with locks and message passing but other forms of
synchronization could be used.
"""
from multiprocessing import Process, Pipe, Lock

#lock used to ensure that two processes do not access a pipe at the same time
processLock = Lock()
Comment on lines +13 to +16
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cclauss We can use the spawn method to start the subprocess. The spawn method is considered safer than the fork method. We will get a warning for the fork method in Python 3.12+.

Suggested change
from multiprocessing import Process, Pipe, Lock
#lock used to ensure that two processes do not access a pipe at the same time
processLock = Lock()
from multiprocessing import Process, Pipe, Lock, set_start_method
set_start_method("spawn", force=True) # set the start method before using the context in `Lock()` below
#lock used to ensure that two processes do not access a pipe at the same time
processLock = Lock()

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! Can you please make this a pull request?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


"""
The function run by the processes that sorts the list

position = the position in the list the prcoess represents, used to know which
neighbor we pass our value to
value = the initial value at list[position]
LSend, RSend = the pipes we use to send to our left and right neighbors
LRcv, RRcv = the pipes we use to receive from our left and right neighbors
resultPipe = the pipe used to send results back to main
"""
def oeProcess(position, value, LSend, RSend, LRcv, RRcv, resultPipe):
global processLock

#we perform n swaps since after n swaps we know we are sorted
#we *could* stop early if we are sorted already, but it takes as long to
#find out we are sorted as it does to sort the list with this algorithm
for i in range(0, 10):

if( (i + position) % 2 == 0 and RSend != None):
#send your value to your right neighbor
processLock.acquire()
RSend[1].send(value)
processLock.release()

#receive your right neighbor's value
processLock.acquire()
temp = RRcv[0].recv()
processLock.release()

#take the lower value since you are on the left
value = min(value, temp)
elif( (i + position) % 2 != 0 and LSend != None):
#send your value to your left neighbor
processLock.acquire()
LSend[1].send(value)
processLock.release()

#receive your left neighbor's value
processLock.acquire()
temp = LRcv[0].recv()
processLock.release()

#take the higher value since you are on the right
value = max(value, temp)
#after all swaps are performed, send the values back to main
resultPipe[1].send(value)

"""
the function which creates the processes that perform the parallel swaps

arr = the list to be sorted
"""
def OddEvenTransposition(arr):

processArray = []
tempRrcv = None
tempLrcv = None

resultPipe = []

#initialize the list of pipes where the values will be retrieved
for a in arr:
resultPipe.append(Pipe())

#creates the processes
#the first and last process only have one neighbor so they are made outside
#of the loop
tempRs = Pipe()
tempRr = Pipe()
processArray.append(Process(target = oeProcess, args = (0, arr[0], None, tempRs, None, tempRr, resultPipe[0])))
tempLr = tempRs
tempLs = tempRr

for i in range(1, len(arr) - 1):
tempRs = Pipe()
tempRr = Pipe()
processArray.append(Process(target = oeProcess, args = (i, arr[i], tempLs, tempRs, tempLr, tempRr, resultPipe[i])))
tempLr = tempRs
tempLs = tempRr

processArray.append(Process(target = oeProcess, args = (len(arr) - 1, arr[len(arr) - 1], tempLs, None, tempLr, None, resultPipe[len(arr) - 1])))

#start the processes
for p in processArray:
p.start()

#wait for the processes to end and write their values to the list
for p in range(0, len(resultPipe)):
arr[p] = resultPipe[p][0].recv()
processArray[p].join()

return(arr)


#creates a reverse sorted list and sorts it
def main():
arr = []

for i in range(10, 0, -1):
arr.append(i)
print("Initial List")
print(*arr)

list = OddEvenTransposition(arr)

print("Sorted List\n")
print(*arr)

if __name__ == "__main__":
main()
32 changes: 32 additions & 0 deletions sorts/Odd-Even_transposition_single-threaded.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""
This is a non-parallelized implementation of odd-even transpostiion sort.

Normally the swaps in each set happen simultaneously, without that the algorithm
is no better than bubble sort.
"""

def OddEvenTransposition(arr):
for i in range(0, len(arr)):
for i in range(i % 2, len(arr) - 1, 2):
if arr[i + 1] < arr[i]:
arr[i], arr[i + 1] = arr[i + 1], arr[i]
print(*arr)

return arr

#creates a list and sorts it
def main():
list = []

for i in range(10, 0, -1):
list.append(i)
print("Initial List")
print(*list)

list = OddEvenTransposition(list)

print("Sorted List\n")
print(*list)

if __name__ == "__main__":
main()