Skip to content

Commit 09ee752

Browse files
committed
Quicksort Reactor implementation with the ability to modify
1 parent 5b53bf7 commit 09ee752

File tree

1 file changed

+242
-0
lines changed

1 file changed

+242
-0
lines changed

src/benchmark/quicksort.ts

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
import {
2+
type WritablePort,
3+
Parameter,
4+
InPort,
5+
OutPort,
6+
State,
7+
Action,
8+
Reactor,
9+
App,
10+
TimeValue,
11+
Origin,
12+
Log,
13+
PrecedenceGraph
14+
} from "../core/internal";
15+
16+
// This is the thrshold for the quicksort algorithm, feeding sorters below this number will use Array.prototype.sort()
17+
// toSorted() is more ideal but I think there is some compatibility issue.
18+
const T = 8;
19+
20+
const arr = [
21+
578, 530, 482, 105, 400, 787, 563, 613, 483, 888, 439, 928, 857, 404, 949,
22+
736, 68, 761, 951, 432, 799, 212, 108, 937, 562, 616, 436, 358, 221, 315, 423,
23+
539, 215, 795, 409, 227, 715, 847, 66, 242, 168, 637, 572, 468, 116, 668, 213,
24+
859, 880, 291, 609, 502, 486, 710, 662, 172, 991, 631, 120, 905, 751, 293,
25+
411, 503, 901, 53, 774, 145, 831, 140, 592, 184, 228, 111, 907, 640, 553, 519,
26+
579, 389, 735, 545, 975, 255, 83, 449, 673, 427, 369, 854, 86, 33, 885, 940,
27+
904, 764, 834, 250, 183, 191
28+
];
29+
30+
Log.global.level = Log.levels.INFO;
31+
32+
// Change the boolean value to toggle between the "matryoshka" version or "flat" version.
33+
const useHierarchy = true;
34+
35+
class QuickSorter extends Reactor {
36+
parentReadPort: InPort<number[]>;
37+
parentWritePort: OutPort<number[]>;
38+
leftWritePort: OutPort<number[]>;
39+
rightWritePort: OutPort<number[]>;
40+
leftReadPort: InPort<number[]>;
41+
rightReadPort: InPort<number[]>;
42+
43+
resultArr: State<number[]>;
44+
numFragments: State<number>;
45+
46+
leftReactor: Reactor | undefined;
47+
rightReactor: Reactor | undefined;
48+
49+
constructor(parent: Reactor, name = "root") {
50+
super(parent, name);
51+
this.parentReadPort = new InPort<number[]>(this);
52+
this.parentWritePort = new OutPort<number[]>(this);
53+
this.leftWritePort = new OutPort<number[]>(this);
54+
this.rightWritePort = new OutPort<number[]>(this);
55+
this.leftReadPort = new InPort<number[]>(this);
56+
this.rightReadPort = new InPort<number[]>(this);
57+
this.resultArr = new State([]);
58+
this.numFragments = new State(0);
59+
60+
// When the parent sends a message, we send it to children.
61+
this.addMutation(
62+
[this.parentReadPort],
63+
[
64+
this.parentReadPort,
65+
this.writable(this.parentWritePort),
66+
this.leftWritePort,
67+
this.rightWritePort,
68+
this.leftReadPort,
69+
this.rightReadPort,
70+
this.resultArr,
71+
this.numFragments
72+
],
73+
function (
74+
this,
75+
parentReadPort,
76+
parentWritePort,
77+
leftWritePort,
78+
rightWritePort,
79+
leftread,
80+
rightread,
81+
resultArr,
82+
numFragments
83+
) {
84+
const hierarchyImplementation = (
85+
useHierarchy
86+
? this.getReactor()._uncheckedAddChild
87+
: this.getReactor()._uncheckedAddSibling
88+
).bind(this.getReactor());
89+
90+
const fullarr = parentReadPort.get();
91+
if (fullarr == null) {
92+
throw Error("Received null from port");
93+
}
94+
if (fullarr.length < T) {
95+
const sorted = [...fullarr].sort((a, b) => a - b);
96+
parentWritePort.set(sorted);
97+
return;
98+
}
99+
const pivot = fullarr[0];
100+
const leftToSort = fullarr.filter((val) => val < pivot);
101+
const righttoSort = fullarr.filter((val) => val > pivot);
102+
const pivots = fullarr.filter((val) => val === pivot);
103+
104+
resultArr.set(pivots);
105+
numFragments.set(numFragments.get() + 1);
106+
107+
console.log(
108+
`I received a request! ${fullarr}! Pivot is ${pivot}, so I divided it into ${leftToSort} and ${righttoSort}`
109+
);
110+
111+
// First, create 2 new reactors
112+
const leftReactor = hierarchyImplementation(
113+
QuickSorter,
114+
`${this.getReactor()._name}/l`
115+
);
116+
const rightReactor = hierarchyImplementation(
117+
QuickSorter,
118+
`${this.getReactor()._name}/r`
119+
);
120+
121+
// Connect ports accoringly
122+
this.connect(leftWritePort, leftReactor.parentReadPort);
123+
this.connect(rightWritePort, rightReactor.parentReadPort);
124+
125+
this.connect(leftReactor.parentWritePort, leftread);
126+
this.connect(rightReactor.parentWritePort, rightread);
127+
128+
this.getReactor().writable(leftWritePort).set(leftToSort);
129+
this.getReactor().writable(rightWritePort).set(righttoSort);
130+
}
131+
);
132+
133+
this.addReaction(
134+
[this.leftReadPort],
135+
[
136+
this.leftReadPort,
137+
this.resultArr,
138+
this.numFragments,
139+
this.writable(this.parentWritePort)
140+
],
141+
function (this, leftreadport, resultArr, numFragments, parentWrite) {
142+
const leftResult = leftreadport.get();
143+
const myResult = resultArr.get();
144+
if (leftResult == null) {
145+
throw Error("Left return null");
146+
}
147+
if (myResult.length === 0) {
148+
throw Error(
149+
"Result length is 0, but should contain at least the pivots."
150+
);
151+
}
152+
153+
console.log(`I received a result from my left! ${leftResult}!`);
154+
resultArr.set([...leftResult, ...myResult]);
155+
156+
numFragments.set(numFragments.get() + 1);
157+
if (numFragments.get() === 3) {
158+
parentWrite.set(resultArr.get());
159+
}
160+
}
161+
);
162+
163+
this.addReaction(
164+
[this.rightReadPort],
165+
[
166+
this.rightReadPort,
167+
this.resultArr,
168+
this.numFragments,
169+
this.writable(this.parentWritePort)
170+
],
171+
function (this, rightreadport, resultArr, numFragments, parentWrite) {
172+
const rightResult = rightreadport.get();
173+
const myResult = resultArr.get();
174+
if (rightResult == null) {
175+
throw Error("Right return null");
176+
}
177+
if (myResult.length === 0) {
178+
throw Error(
179+
"Result length is 0, but should contain at least the pivots."
180+
);
181+
}
182+
183+
console.log(`I received a result from my right! ${rightResult}!`);
184+
resultArr.set([...myResult, ...rightResult]);
185+
186+
numFragments.set(numFragments.get() + 1);
187+
if (numFragments.get() === 3) {
188+
parentWrite.set(resultArr.get());
189+
}
190+
}
191+
);
192+
}
193+
}
194+
195+
class Supplier extends Reactor {
196+
rootWritePort: OutPort<number[]>;
197+
rootReadPort: InPort<number[]>;
198+
199+
constructor(parent: Reactor, arr: number[], name = "Innocent Supplier") {
200+
super(parent, name);
201+
this.rootWritePort = new OutPort<number[]>(this);
202+
this.rootReadPort = new InPort<number[]>(this);
203+
this.addReaction(
204+
[this.startup],
205+
[this.writable(this.rootWritePort)],
206+
function (this, rootwrite) {
207+
rootwrite.set(arr);
208+
}
209+
);
210+
211+
this.addReaction(
212+
[this.rootReadPort],
213+
[this.rootReadPort],
214+
function (this, rootReadPort) {
215+
console.log(`I received final result: ${rootReadPort.get() ?? "null"}`);
216+
}
217+
);
218+
}
219+
}
220+
221+
class Arbiter extends App {
222+
rootSorter: QuickSorter;
223+
supplier: Supplier;
224+
225+
constructor(
226+
name: string,
227+
timeout: TimeValue | undefined = undefined,
228+
keepAlive = false,
229+
fast = false,
230+
success?: () => void,
231+
fail?: () => void
232+
) {
233+
super(timeout, keepAlive, fast, success, fail, name);
234+
this.rootSorter = new QuickSorter(this, "root");
235+
this.supplier = new Supplier(this, arr);
236+
this._connect(this.supplier.rootWritePort, this.rootSorter.parentReadPort);
237+
this._connect(this.rootSorter.parentWritePort, this.supplier.rootReadPort);
238+
}
239+
}
240+
241+
const arb = new Arbiter("arbiter");
242+
arb._start();

0 commit comments

Comments
 (0)