Skip to content

Commit

Permalink
Add shuffle function and testing script
Browse files Browse the repository at this point in the history
Implement q_shuffle function using the Fisher–Yates shuffle
algorithm, allowing the reordering of a queue. Next, using shuffle.py,
we will observe the frequency of occurrences of the permutations of
1234 to create a statistical chart. The frequency in the chart roughly
follows a uniform distribution.
  • Loading branch information
HotMercury committed Mar 3, 2024
1 parent 59703e4 commit f237c7d
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 0 deletions.
23 changes: 23 additions & 0 deletions qtest.c
Original file line number Diff line number Diff line change
Expand Up @@ -579,6 +579,28 @@ static bool do_size(int argc, char *argv[])
return ok && !error_check();
}

extern void q_shuffle(struct list_head *q);
bool do_shuffle(int argc, char *argv[])
{
if (argc != 1) {
report(1, "%s takes no arguments", argv[0]);
return false;
}

if (!current || !current->q)
report(3, "Warning: Calling reverse on null queue");
error_check();

set_noallocate_mode(true);
if (current && exception_setup(true))
q_shuffle(current->q);
exception_cancel();

set_noallocate_mode(false);
q_show(3);
return !error_check();
}

bool do_sort(int argc, char *argv[])
{
if (argc != 1) {
Expand Down Expand Up @@ -1035,6 +1057,7 @@ static void console_init()
"Remove from tail of queue. Optionally compare to expected value str",
"[str]");
ADD_COMMAND(reverse, "Reverse queue", "");
ADD_COMMAND(shuffle, "Do Fisher-Yates shuffle", "");
ADD_COMMAND(sort, "Sort queue in ascending/descening order", "");
ADD_COMMAND(size, "Compute queue size n times (default: n == 1)", "[n]");
ADD_COMMAND(show, "Show queue contents", "");
Expand Down
21 changes: 21 additions & 0 deletions queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,3 +365,24 @@ int q_merge(struct list_head *head, bool descend)
}
return count;
}

void q_shuffle(struct list_head *head)
{
if (!head || list_empty(head) || list_is_singular(head)) {
return;
}
int size = q_size(head);
for (struct list_head *node = head->prev; node != head && size;
node = node->prev, size--) {
struct list_head *it = head->next;
// find random node
for (int r = rand() % size; r > 0; r--) {
it = it->next;
}
if (it == node) {
continue;
}
struct list_head *tmp = head->prev;
list_move(it, tmp);
}
}
75 changes: 75 additions & 0 deletions scripts/shuffle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import subprocess
import re
import random
from itertools import permutations
import matplotlib.pyplot as plt
import numpy as np

def permute(nums):
nums = list(permutations(nums, len(nums)))
return nums

def chiSquared(observation, expectation):
return ((observation - expectation) ** 2) / expectation

# 產生測試數據
test_count = 1000000
input_data = "new\nit 1\nit 2\nit 3\nit 4\n"
for i in range(test_count):
input_data += "shuffle\n"
input_data += "free\nquit\n"

# 執行子進程
command = './qtest -v 3'
command_list = command.split()
completed_process = subprocess.run(command_list, capture_output=True, text=True, input=input_data)
output_data = completed_process.stdout

# 提取數據
start_idx = output_data.find("l = [1 2 3 4]")
end_idx = output_data.find("l = NULL")
output_data = output_data[start_idx + 14: end_idx]
regex = re.compile(r'\d \d \d \d')
result = regex.findall(output_data)

# 整理數據
nums = [i.split() for i in result]

# 找出全部的排序可能
counter_set = {}
shuffle_array = ['1', '2', '3', '4']
s = permute(shuffle_array)

# 初始化 counter_set
for i in range(len(s)):
w = ''.join(s[i])
counter_set[w] = 0

# 計算每一種 shuffle 結果的數量
for num in nums:
permutation = ''.join(num)
counter_set[permutation] += 1

# 計算 chiSquare sum
expectation = test_count // len(s)
c = counter_set.values()
chi_squared_sum = 0
for i in c:
chi_squared_sum += chiSquared(i, expectation)

# 顯示統計結果
print("Expectation: ", expectation)
print("Observation: ", counter_set)
print("chi square sum: ", chi_squared_sum)

# 繪製條形圖
counts_list = list(counter_set.values())

# 使用 1 到 24 作為 x 軸座標
x = np.arange(1, 25)

plt.bar(x, counts_list)
plt.xlabel('permutations')
plt.ylabel('counts')
plt.title('Shuffle result')
plt.show()

0 comments on commit f237c7d

Please sign in to comment.