Skip to content

Commit 466ee7a

Browse files
committed
One hand per thread, thread test all branches
1 parent 5a0148e commit 466ee7a

File tree

1 file changed

+78
-40
lines changed

1 file changed

+78
-40
lines changed

simulation/Simulation.java

Lines changed: 78 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.concurrent.atomic.AtomicInteger;
2424
import java.util.function.BiPredicate;
2525
import java.util.function.BooleanSupplier;
26+
import java.util.function.Consumer;
2627
import java.util.function.Supplier;
2728
import java.util.stream.Collectors;
2829
import java.util.stream.Stream;
@@ -252,19 +253,19 @@ public static AtomicInteger[] initialize_array(final int LENGTH)
252253
*/
253254
public static <C extends Collection<Scenario>> ArrayList<Scenario> purify_forest(final C RAW_FOREST)
254255
{
255-
ArrayList<Scenario> filtered_trees = new ArrayList<Scenario>(RAW_FOREST.parallelStream().filter(tree -> tree.DISPLAY).collect(Collectors.toList()));
256+
ArrayList<Scenario> filtered_trees = RAW_FOREST.parallelStream().filter(tree -> tree.DISPLAY).collect(Collectors.toCollection(ArrayList::new));
256257
filtered_trees.trimToSize();
257258
return filtered_trees;
258259
}
259260

260261
/**
261262
* Subroutine to draw a hand. Note, returns shallow.
262-
*
263+
*
263264
* @param <R> the type of cards in the deck
264-
*
265+
*
265266
* @param HAND_SIZE to draw, should be >= DECK's size
266267
* @param DECK to draw from
267-
*
268+
*
268269
* @return created hand, backed ({@link ArrayList#subList(int, int)}) by the original deck
269270
*/
270271
public static <R extends Reservable> ArrayList<R> draw_hand(final int HAND_SIZE, final ArrayList<R> DECK)
@@ -273,6 +274,41 @@ public static <R extends Reservable> ArrayList<R> draw_hand(final int HAND_SIZE,
273274
return new ArrayList<R>(DECK.subList(0, HAND_SIZE));
274275
}
275276

277+
/**
278+
* Subroutine to draw a hand. Note, returns shallow.
279+
*
280+
* @param <R> the type of cards in the deck
281+
*
282+
* @param HAND_SIZE to draw, should be >= DECK's size
283+
* @param DECK to draw from
284+
*
285+
* @return created hand, backed ({@link ArrayList#subList(int, int)}) by the original deck
286+
*/
287+
public static <R extends Reservable> ArrayList<R> sample_hand(final int HAND_SIZE, final ArrayList<R> DECK, Random r)
288+
{
289+
// Based on libstdc++'s implementation of std::sample
290+
ArrayList<R> toReturn = new ArrayList<>(HAND_SIZE);
291+
Iterator<R> inputIterator = DECK.iterator();
292+
293+
int unsampled_size = DECK.size();
294+
int n = Math.min(HAND_SIZE, unsampled_size);
295+
296+
for (R current = inputIterator.next(); n != 0; current = inputIterator.next()) {
297+
if(r.nextInt(--unsampled_size) < n) {
298+
toReturn.add(current);
299+
--n;
300+
}
301+
}
302+
303+
return toReturn;
304+
}
305+
306+
public static <R extends Reservable> ArrayList<R> draw_hand(final int HAND_SIZE, final ArrayList<R> DECK, Random rnd)
307+
{
308+
Collections.shuffle(DECK, rnd);
309+
return new ArrayList<R>(DECK.subList(0, HAND_SIZE));
310+
}
311+
276312
/**
277313
* Frees all cards in hand. {@link Reservable#release()}
278314
*
@@ -302,6 +338,7 @@ public String simulate(final boolean OVERRIDE, final int HAND_SIZE, final int TE
302338
final int CORE_COUNT = Runtime.getRuntime().availableProcessors();
303339

304340
if (CORE_COUNT > 1)
341+
// return this.parallel_simulation(CORE_COUNT, HAND_SIZE, TEST_HAND_COUNT);
305342
return this.parallel_simulation2(HAND_SIZE, TEST_HAND_COUNT);
306343
else if (CORE_COUNT == 1)
307344
return Simulation.sequential_simulation(HAND_SIZE, TEST_HAND_COUNT, this.DECK, this.FOREST);
@@ -321,52 +358,49 @@ class ScenarioCount {
321358
this.equation = equation;
322359
this.count = new AtomicInteger();
323360
}
324-
}
325361

326-
class Equation implements Runnable {
327-
final ScenarioCount scenario;
328-
final ArrayList<Deck_Card> hand;
329-
330-
Equation(ScenarioCount equation, ArrayList<Deck_Card> hand) {
331-
this.scenario = equation;
332-
this.hand = hand;
362+
void run_hand(ArrayList<Deck_Card> hand) {
363+
if (this.equation.evaluate(hand)) {
364+
this.count.incrementAndGet();
365+
}
333366
}
367+
}
368+
369+
final List<ScenarioCount> forestCount = FOREST.stream().map(ScenarioCount::new).collect(Collectors.toList());
334370

335-
public void run() {
336-
if (this.scenario.equation.evaluate(this.hand)) {
337-
this.scenario.count.incrementAndGet();
371+
/*
372+
Minimalist Strategy
373+
Only create a single thread for each drawn hand, and have each hand test all scenarios
374+
*/
375+
class HandGenerator implements Supplier<ArrayList<Deck_Card>> {
376+
@Override
377+
public ArrayList<Deck_Card> get() {
378+
synchronized (DECK) {
379+
return Deck_Card.deep_copy(draw_hand(HAND_SIZE, DECK));
338380
}
339381
}
340382
}
341383

342-
class EquationLooper implements Supplier<Equation> {
343-
Iterator<ScenarioCount> current;
344-
final List<ScenarioCount> list = FOREST.stream().map(ScenarioCount::new).collect(Collectors.toList());
345-
ArrayList<Deck_Card> hand;
346-
384+
class HandTester implements Consumer<ArrayList<Deck_Card>> {
347385
@Override
348-
public Equation get() {
349-
synchronized (list) {
350-
if (current == null || !current.hasNext()) {
351-
hand = draw_hand(HAND_SIZE, DECK);
352-
current = list.iterator();
353-
}
354-
return new Equation(current.next(), Deck_Card.deep_copy(hand));
386+
public void accept(ArrayList<Deck_Card> hand) {
387+
for(ScenarioCount sc : forestCount) {
388+
sc.run_hand(hand);
389+
reset_hand(hand);
355390
}
356391
}
357392
}
358393

394+
359395
final long START_TIME; //simulation start time in milliseconds
360396

361397
synchronized (Simulation.PARALLEL_SIMULATION_LOCK) {
362398
START_TIME = System.currentTimeMillis();
363-
EquationLooper evaluator = new EquationLooper();
364-
final int FOREST_SIZE = this.FOREST.size();
365399

366-
Stream<Equation> loopingScenario = Stream.generate(evaluator);
367-
loopingScenario.parallel().limit((long) FOREST_SIZE * TEST_HAND_COUNT).forEach(Equation::run);
400+
Stream<ArrayList<Deck_Card>> random_hands = Stream.generate(new HandGenerator());
401+
random_hands.parallel().limit(TEST_HAND_COUNT).forEach(new HandTester());
368402

369-
AtomicInteger[] HITS = evaluator.list.stream().map(a -> a.count).toArray(AtomicInteger[]::new);
403+
AtomicInteger[] HITS = forestCount.stream().map(a -> a.count).toArray(AtomicInteger[]::new);
370404

371405
return Simulation.assemble_results_subroutine(HAND_SIZE, TEST_HAND_COUNT, START_TIME, HITS, this.FOREST);
372406
}
@@ -391,12 +425,12 @@ class Hand_Tester implements Runnable
391425
/**
392426
* Counts number of times this test has passed.
393427
*/
394-
private final AtomicInteger HIT_COUNTER;
428+
private final AtomicInteger[] HIT_COUNTER;
395429

396430
/**
397431
* How to test hand.
398432
*/
399-
private final Scenario EQUATION;
433+
private final ArrayList<Scenario> EQUATION;
400434

401435
/**
402436
* Hand to be tested.
@@ -410,7 +444,7 @@ class Hand_Tester implements Runnable
410444
* @param EQUATION to perform testing on {@link #TEST_HAND}
411445
* @param TEST_HAND to be tested by {@link #EQUATION}
412446
*/
413-
public Hand_Tester(final AtomicInteger HIT_COUNTER, final Scenario EQUATION, final ArrayList<Deck_Card> TEST_HAND)
447+
public Hand_Tester(final AtomicInteger[] HIT_COUNTER, final ArrayList<Scenario> EQUATION, final ArrayList<Deck_Card> TEST_HAND)
414448
{
415449
this.HIT_COUNTER = HIT_COUNTER;
416450
this.EQUATION = EQUATION;
@@ -420,8 +454,12 @@ public Hand_Tester(final AtomicInteger HIT_COUNTER, final Scenario EQUATION, fin
420454
@Override
421455
public void run()
422456
{
423-
if (this.EQUATION.evaluate(this.TEST_HAND))
424-
this.HIT_COUNTER.incrementAndGet();
457+
for (int i = 0; i < this.EQUATION.size(); ++i) {
458+
Scenario branch = this.EQUATION.get(i);
459+
if (branch.evaluate(this.TEST_HAND))
460+
this.HIT_COUNTER[i].incrementAndGet();
461+
reset_hand(this.TEST_HAND);
462+
}
425463
}
426464
}
427465

@@ -553,6 +591,8 @@ protected void modulate_parallelization()
553591
//control partition size
554592
{
555593
final int BLOCKING_QUEUE_SIZE = this.TASK_OVERSEER.getQueue().size();
594+
/*System.err.printf("Blocking queue size: %d, Completed Tasks: %d, Available Processors: %d, Partition Count %d, Partition Size %d\n",
595+
BLOCKING_QUEUE_SIZE, this.TASK_OVERSEER.getTaskCount(), Runtime.getRuntime().availableProcessors(), this.partition_count, this.partition_size);*/
556596
//Magic numbers have been tested to be rather good, also feels right as well.
557597
final int UPPER_THRESHOLD = 125;
558598
final int LOWER_THRESHOLD = 25;
@@ -589,9 +629,7 @@ protected void run_subroutine(final int START, final int END)
589629
current_hand = Deck_Card.deep_copy(draw_hand(HAND_SIZE, this.DECK));
590630
}
591631

592-
this.TASK_OVERSEER.execute(new Hand_Tester(this.HITS[0], this.FOREST.get(0), current_hand));
593-
for (int j = 1; j < this.FOREST.size(); ++j)
594-
this.TASK_OVERSEER.execute(new Hand_Tester(this.HITS[j], this.FOREST.get(j), Deck_Card.deep_copy(current_hand)));
632+
this.TASK_OVERSEER.execute(new Hand_Tester(this.HITS, this.FOREST, current_hand));
595633
}
596634
}
597635
}

0 commit comments

Comments
 (0)