|
12 | 12 | """ |
13 | 13 |
|
14 | 14 | import multiprocessing as mp |
| 15 | +from typing import Any, Protocol |
15 | 16 |
|
16 | 17 | # lock used to ensure that two processes do not access a pipe at the same time |
17 | 18 | # NOTE This breaks testing on build runner. May work better locally |
18 | 19 | # process_lock = mp.Lock() |
19 | 20 |
|
20 | | -""" |
21 | | -The function run by the processes that sorts the list |
22 | | -
|
23 | | -position = the position in the list the process represents, used to know which |
24 | | - neighbor we pass our value to |
25 | | -value = the initial value at list[position] |
26 | | -LSend, RSend = the pipes we use to send to our left and right neighbors |
27 | | -LRcv, RRcv = the pipes we use to receive from our left and right neighbors |
28 | | -resultPipe = the pipe used to send results back to main |
29 | | -""" |
30 | 21 |
|
| 22 | +class Comparable(Protocol): |
| 23 | + def __lt__(self, other: Any, /) -> bool: ... |
31 | 24 |
|
32 | | -def oe_process( |
33 | | - position, |
34 | | - value, |
35 | | - l_send, |
36 | | - r_send, |
37 | | - lr_cv, |
38 | | - rr_cv, |
39 | | - result_pipe, |
40 | | - multiprocessing_context, |
| 25 | + |
| 26 | +def oe_process[T: Comparable]( |
| 27 | + position: int, |
| 28 | + value: T, |
| 29 | + l_send: tuple[mp.connection.Connection, mp.connection.Connection] | None, |
| 30 | + r_send: tuple[mp.connection.Connection, mp.connection.Connection] | None, |
| 31 | + lr_cv: tuple[mp.connection.Connection, mp.connection.Connection] | None, |
| 32 | + rr_cv: tuple[mp.connection.Connection, mp.connection.Connection] | None, |
| 33 | + result_pipe: tuple[mp.connection.Connection, mp.connection.Connection], |
| 34 | + multiprocessing_context: Any, |
41 | 35 | ) -> None: |
| 36 | + """ |
| 37 | + The function run by the processes that sorts the list. |
| 38 | +
|
| 39 | + position = the position in the list the process represents, used to know |
| 40 | + which neighbor we pass our value to |
| 41 | + value = the initial value at list[position] |
| 42 | + l_send, r_send = the pipes we use to send to our left and right neighbors |
| 43 | + lr_cv, rr_cv = the pipes we use to receive from our left and right |
| 44 | + neighbors |
| 45 | + result_pipe = the pipe used to send results back to main |
| 46 | + """ |
42 | 47 | process_lock = multiprocessing_context.Lock() |
43 | 48 |
|
44 | 49 | # we perform n swaps since after n swaps we know we are sorted |
@@ -71,33 +76,34 @@ def oe_process( |
71 | 76 | result_pipe[1].send(value) |
72 | 77 |
|
73 | 78 |
|
74 | | -""" |
75 | | -the function which creates the processes that perform the parallel swaps |
76 | | -
|
77 | | -arr = the list to be sorted |
78 | | -""" |
79 | | - |
80 | | - |
81 | | -def odd_even_transposition(arr): |
| 79 | +def odd_even_transposition[T: Comparable](arr: list[T]) -> list[T]: |
82 | 80 | """ |
83 | | - >>> odd_even_transposition(list(range(10)[::-1])) == sorted(list(range(10)[::-1])) |
84 | | - True |
85 | | - >>> odd_even_transposition(["a", "x", "c"]) == sorted(["x", "a", "c"]) |
86 | | - True |
87 | | - >>> odd_even_transposition([1.9, 42.0, 2.8]) == sorted([1.9, 42.0, 2.8]) |
88 | | - True |
89 | | - >>> odd_even_transposition([False, True, False]) == sorted([False, False, True]) |
90 | | - True |
91 | | - >>> odd_even_transposition([1, 32.0, 9]) == sorted([False, False, True]) |
92 | | - False |
93 | | - >>> odd_even_transposition([1, 32.0, 9]) == sorted([1.0, 32, 9.0]) |
| 81 | + Sort a list of comparable items using the parallel odd-even transposition |
| 82 | + sort algorithm. |
| 83 | +
|
| 84 | + Each element is represented by a separate process; neighboring processes |
| 85 | + exchange values in alternating odd/even rounds via message-passing pipes. |
| 86 | + Items must be mutually comparable (support ``<``); passing a list whose |
| 87 | + elements cannot be compared with each other (e.g. mixing ``int`` and |
| 88 | + ``str``) raises ``TypeError`` inside the worker processes. |
| 89 | +
|
| 90 | + :param arr: a list of mutually comparable items |
| 91 | + :return: the same list sorted in ascending order |
| 92 | +
|
| 93 | + Examples: |
| 94 | + >>> odd_even_transposition([5, 4, 3, 2, 1]) |
| 95 | + [1, 2, 3, 4, 5] |
| 96 | + >>> odd_even_transposition([3, 3, 1, 2, 2, 1]) |
| 97 | + [1, 1, 2, 2, 3, 3] |
| 98 | + >>> odd_even_transposition(['c', 'a', 'b']) |
| 99 | + ['a', 'b', 'c'] |
| 100 | + >>> odd_even_transposition([3.3, 1.1, 2.2]) |
| 101 | + [1.1, 2.2, 3.3] |
| 102 | + >>> odd_even_transposition(list(range(10)[::-1])) == sorted(range(10)) |
94 | 103 | True |
95 | 104 | >>> unsorted_list = [-442, -98, -554, 266, -491, 985, -53, -529, 82, -429] |
96 | 105 | >>> odd_even_transposition(unsorted_list) == sorted(unsorted_list) |
97 | 106 | True |
98 | | - >>> unsorted_list = [-442, -98, -554, 266, -491, 985, -53, -529, 82, -429] |
99 | | - >>> odd_even_transposition(unsorted_list) == sorted(unsorted_list + [1]) |
100 | | - False |
101 | 107 | """ |
102 | 108 | # spawn method is considered safer than fork |
103 | 109 | multiprocessing_context = mp.get_context("spawn") |
|
0 commit comments