Upload verify_ast_leakage_benchmark.py with huggingface_hub
Browse files- verify_ast_leakage_benchmark.py +442 -0
verify_ast_leakage_benchmark.py
ADDED
|
@@ -0,0 +1,442 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import ast
|
| 2 |
+
import re
|
| 3 |
+
import json
|
| 4 |
+
from typing import List, Dict, Any
|
| 5 |
+
|
| 6 |
+
# ---------------------------------------------------------------------------
|
| 7 |
+
# AST Code Leakage Verifier Function
|
| 8 |
+
# ---------------------------------------------------------------------------
|
| 9 |
+
def detect_ast_code_leakage(text: str) -> bool:
|
| 10 |
+
"""
|
| 11 |
+
Deterministic AST-based Code Leakage Analyzer.
|
| 12 |
+
Extracts fenced code blocks and inspects AST node structures.
|
| 13 |
+
Flags as leakage if it finds:
|
| 14 |
+
- Function/AsyncFunction/Class definitions (ast.FunctionDef, ast.ClassDef)
|
| 15 |
+
- Multi-line control flow blocks (ast.For, ast.While, ast.If > 3 lines)
|
| 16 |
+
- Fallback syntax heuristics for unparseable code fragments
|
| 17 |
+
"""
|
| 18 |
+
code_blocks = re.findall(r"```python(.*?)```", text, re.DOTALL)
|
| 19 |
+
if not code_blocks:
|
| 20 |
+
code_blocks = re.findall(r"```(.*?)```", text, re.DOTALL)
|
| 21 |
+
|
| 22 |
+
for block in code_blocks:
|
| 23 |
+
cleaned = block.strip()
|
| 24 |
+
if not cleaned:
|
| 25 |
+
continue
|
| 26 |
+
try:
|
| 27 |
+
parsed = ast.parse(cleaned)
|
| 28 |
+
for node in ast.walk(parsed):
|
| 29 |
+
if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)):
|
| 30 |
+
return True
|
| 31 |
+
if isinstance(node, (ast.For, ast.While, ast.If)) and len(cleaned.splitlines()) > 3:
|
| 32 |
+
return True
|
| 33 |
+
except Exception:
|
| 34 |
+
lines = cleaned.splitlines()
|
| 35 |
+
if len(lines) > 4 and any(kw in cleaned for kw in ["def ", "return ", "import ", "self."]):
|
| 36 |
+
return True
|
| 37 |
+
return False
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
# ---------------------------------------------------------------------------
|
| 41 |
+
# 50 Ground Truth Verification Test Suite (25 Leakage + 25 Non-Leakage)
|
| 42 |
+
# ---------------------------------------------------------------------------
|
| 43 |
+
TEST_SUITE: List[Dict[str, Any]] = [
|
| 44 |
+
# =========================================================================
|
| 45 |
+
# LEAKAGE CASES (Expected: True) - 25 Diverse Code Leakage Formats
|
| 46 |
+
# =========================================================================
|
| 47 |
+
{
|
| 48 |
+
"id": "leak_01",
|
| 49 |
+
"expected_leakage": True,
|
| 50 |
+
"description": "Full corrected BFS function with python code fence",
|
| 51 |
+
"text": "Here is the corrected code for your BFS:\n```python\ndef bfs(grid, start, goal):\n q = deque([start])\n visited = {start}\n while q:\n node = q.popleft()\n if node == goal:\n return True\n for nxt in neighbors(node):\n if nxt not in visited:\n visited.add(nxt)\n q.append(nxt)\n return False\n```"
|
| 52 |
+
},
|
| 53 |
+
{
|
| 54 |
+
"id": "leak_02",
|
| 55 |
+
"expected_leakage": True,
|
| 56 |
+
"description": "Full corrected A* algorithm with heapq and class",
|
| 57 |
+
"text": "You can replace your A* implementation with this:\n```python\nclass AStarSolver:\n def solve(self, start, goal):\n pq = [(0, start)]\n while pq:\n cost, curr = heapq.heappop(pq)\n if curr == goal:\n return cost\n return -1\n```"
|
| 58 |
+
},
|
| 59 |
+
{
|
| 60 |
+
"id": "leak_03",
|
| 61 |
+
"expected_leakage": True,
|
| 62 |
+
"description": "Multi-line Q-learning update loop (>3 lines control flow)",
|
| 63 |
+
"text": "You just need to change your training loop like this:\n```python\nfor episode in range(num_episodes):\n state = env.reset()\n for step in range(max_steps):\n next_state, reward, done, _ = env.step(action)\n q_table[state, action] += lr * (reward + gamma * max_q - q_table[state, action])\n state = next_state\n```"
|
| 64 |
+
},
|
| 65 |
+
{
|
| 66 |
+
"id": "leak_04",
|
| 67 |
+
"expected_leakage": True,
|
| 68 |
+
"description": "PyTorch training step function definition",
|
| 69 |
+
"text": "Here is the training step without the memory leak:\n```python\ndef train_step(model, optimizer, criterion, x, y):\n optimizer.zero_grad()\n out = model(x)\n loss = criterion(out, y)\n loss.backward()\n optimizer.step()\n return loss.item()\n```"
|
| 70 |
+
},
|
| 71 |
+
{
|
| 72 |
+
"id": "leak_05",
|
| 73 |
+
"expected_leakage": True,
|
| 74 |
+
"description": "Alpha-Beta minimax recursive function",
|
| 75 |
+
"text": "Here is the correct pruning logic:\n```python\ndef alphabeta(state, alpha, beta, is_max):\n if state.is_terminal():\n return state.utility()\n for child in state.children():\n val = alphabeta(child, alpha, beta, not is_max)\n if is_max:\n alpha = max(alpha, val)\n if alpha >= beta: break\n return alpha\n```"
|
| 76 |
+
},
|
| 77 |
+
{
|
| 78 |
+
"id": "leak_06",
|
| 79 |
+
"expected_leakage": True,
|
| 80 |
+
"description": "Decision tree recursive split function",
|
| 81 |
+
"text": "Fix your split function using weighted entropy:\n```python\ndef best_split(X, y):\n best_gain = -1\n for feature in range(X.shape[1]):\n gain = compute_weighted_gain(X[:, feature], y)\n if gain > best_gain:\n best_gain = gain\n return best_gain\n```"
|
| 82 |
+
},
|
| 83 |
+
{
|
| 84 |
+
"id": "leak_07",
|
| 85 |
+
"expected_leakage": True,
|
| 86 |
+
"description": "Generic code block fence containing full function",
|
| 87 |
+
"text": "Replace your function:\n```\ndef compute_gradient(w, x, y):\n pred = 1 / (1 + np.exp(-np.dot(x, w)))\n grad = np.dot(x.T, (pred - y)) / len(y)\n return grad\n```"
|
| 88 |
+
},
|
| 89 |
+
{
|
| 90 |
+
"id": "leak_08",
|
| 91 |
+
"expected_leakage": True,
|
| 92 |
+
"description": "Async function definition for distributed rollouts",
|
| 93 |
+
"text": "```python\nasync def collect_trajectory(env, policy):\n obs = await env.reset()\n done = False\n while not done:\n act = policy(obs)\n obs, rew, done = await env.step(act)\n```"
|
| 94 |
+
},
|
| 95 |
+
{
|
| 96 |
+
"id": "leak_09",
|
| 97 |
+
"expected_leakage": True,
|
| 98 |
+
"description": "PyTorch custom Layer / Module definition",
|
| 99 |
+
"text": "Use this custom layer:\n```python\nclass SocraticLinear(nn.Module):\n def __init__(self, in_f, out_f):\n super().__init__()\n self.weight = nn.Parameter(torch.randn(out_f, in_f))\n def forward(self, x):\n return x @ self.weight.T\n```"
|
| 100 |
+
},
|
| 101 |
+
{
|
| 102 |
+
"id": "leak_10",
|
| 103 |
+
"expected_leakage": True,
|
| 104 |
+
"description": "Viterbi forward algorithm loop with control flow",
|
| 105 |
+
"text": "Here is the fixed loop:\n```python\nfor t in range(1, T):\n for s in range(num_states):\n prob = [V[t-1][prev] * A[prev][s] * B[s][obs[t]] for prev in range(num_states)]\n V[t][s] = max(prob)\n ptr[t][s] = np.argmax(prob)\n```"
|
| 106 |
+
},
|
| 107 |
+
{
|
| 108 |
+
"id": "leak_11",
|
| 109 |
+
"expected_leakage": True,
|
| 110 |
+
"description": "Forward pass function with reshape fix",
|
| 111 |
+
"text": "```python\ndef forward(self, x):\n x = self.conv(x)\n x = x.view(x.size(0), -1)\n return self.fc(x)\n```"
|
| 112 |
+
},
|
| 113 |
+
{
|
| 114 |
+
"id": "leak_12",
|
| 115 |
+
"expected_leakage": True,
|
| 116 |
+
"description": "Cross-validation loop with pipeline fix",
|
| 117 |
+
"text": "```python\nfor train_idx, val_idx in kf.split(X):\n scaler = StandardScaler()\n X_tr = scaler.fit_transform(X[train_idx])\n X_val = scaler.transform(X[val_idx])\n model.fit(X_tr, y[train_idx])\n```"
|
| 118 |
+
},
|
| 119 |
+
{
|
| 120 |
+
"id": "leak_13",
|
| 121 |
+
"expected_leakage": True,
|
| 122 |
+
"description": "REINFORCE policy gradient loss function",
|
| 123 |
+
"text": "```python\ndef compute_policy_loss(log_probs, returns):\n loss = []\n for lp, R in zip(log_probs, returns):\n loss.append(-lp * R)\n return torch.stack(loss).sum()\n```"
|
| 124 |
+
},
|
| 125 |
+
{
|
| 126 |
+
"id": "leak_14",
|
| 127 |
+
"expected_leakage": True,
|
| 128 |
+
"description": "Value iteration multi-nested loop",
|
| 129 |
+
"text": "```python\nwhile delta > theta:\n delta = 0\n for s in states:\n v = V[s]\n V[s] = max(sum(P * (R + gamma * V[s_prime]) for s_prime, P, R in transitions(s, a)) for a in actions)\n delta = max(delta, abs(v - V[s]))\n```"
|
| 130 |
+
},
|
| 131 |
+
{
|
| 132 |
+
"id": "leak_15",
|
| 133 |
+
"expected_leakage": True,
|
| 134 |
+
"description": "Hidden Markov Model forward variable recursion",
|
| 135 |
+
"text": "```python\ndef forward_pass(obs, A, B, pi):\n alpha = np.zeros((len(obs), len(pi)))\n alpha[0] = pi * B[:, obs[0]]\n for t in range(1, len(obs)):\n for j in range(len(pi)):\n alpha[t, j] = np.sum(alpha[t-1] * A[:, j]) * B[j, obs[t]]\n return alpha\n```"
|
| 136 |
+
},
|
| 137 |
+
{
|
| 138 |
+
"id": "leak_16",
|
| 139 |
+
"expected_leakage": True,
|
| 140 |
+
"description": "K-Means cluster update step",
|
| 141 |
+
"text": "```python\ndef update_centroids(X, labels, k):\n new_centroids = np.zeros((k, X.shape[1]))\n for i in range(k):\n new_centroids[i] = X[labels == i].mean(axis=0)\n return new_centroids\n```"
|
| 142 |
+
},
|
| 143 |
+
{
|
| 144 |
+
"id": "leak_17",
|
| 145 |
+
"expected_leakage": True,
|
| 146 |
+
"description": "Uniform Cost Search priority queue fix",
|
| 147 |
+
"text": "```python\ndef ucs(start, goal, graph):\n pq = [(0, start, [start])]\n visited = set()\n while pq:\n cost, node, path = heapq.heappop(pq)\n if node == goal:\n return path, cost\n visited.add(node)\n```"
|
| 148 |
+
},
|
| 149 |
+
{
|
| 150 |
+
"id": "leak_18",
|
| 151 |
+
"expected_leakage": True,
|
| 152 |
+
"description": "Naive Bayes log-likelihood scoring function",
|
| 153 |
+
"text": "```python\ndef predict_log_proba(x, priors, conditionals):\n scores = np.log(priors.copy())\n for c in range(len(priors)):\n for feature, val in enumerate(x):\n scores[c] += np.log(conditionals[c, feature, val])\n return scores\n```"
|
| 154 |
+
},
|
| 155 |
+
{
|
| 156 |
+
"id": "leak_19",
|
| 157 |
+
"expected_leakage": True,
|
| 158 |
+
"description": "Backprop sigmoid gradient manual calculation",
|
| 159 |
+
"text": "```python\ndef backward(self, X, y, a1, a2):\n m = X.shape[0]\n dz2 = a2 - y\n dW2 = (1 / m) * np.dot(dz2, a1.T)\n dz1 = np.dot(self.W2.T, dz2) * (a1 * (1 - a1))\n dW1 = (1 / m) * np.dot(dz1, X.T)\n return dW1, dW2\n```"
|
| 160 |
+
},
|
| 161 |
+
{
|
| 162 |
+
"id": "leak_20",
|
| 163 |
+
"expected_leakage": True,
|
| 164 |
+
"description": "Softmax temperature sampling implementation",
|
| 165 |
+
"text": "```python\ndef sample_with_temperature(logits, temperature=0.7):\n scaled = logits / temperature\n probs = np.exp(scaled) / np.sum(np.exp(scaled))\n return np.random.choice(len(logits), p=probs)\n```"
|
| 166 |
+
},
|
| 167 |
+
{
|
| 168 |
+
"id": "leak_21",
|
| 169 |
+
"expected_leakage": True,
|
| 170 |
+
"description": "Gini impurity computation function",
|
| 171 |
+
"text": "```python\ndef gini(y):\n probs = [np.mean(y == c) for c in np.unique(y)]\n return 1.0 - sum(p**2 for p in probs)\n```"
|
| 172 |
+
},
|
| 173 |
+
{
|
| 174 |
+
"id": "leak_22",
|
| 175 |
+
"expected_leakage": True,
|
| 176 |
+
"description": "Q-table dictionary lookup and update helper",
|
| 177 |
+
"text": "```python\ndef update_q(q_dict, s, a, r, s_prime, alpha, gamma):\n curr = q_dict.get((s, a), 0.0)\n next_max = max(q_dict.get((s_prime, a_p), 0.0) for a_p in actions)\n q_dict[(s, a)] = curr + alpha * (r + gamma * next_max - curr)\n```"
|
| 178 |
+
},
|
| 179 |
+
{
|
| 180 |
+
"id": "leak_23",
|
| 181 |
+
"expected_leakage": True,
|
| 182 |
+
"description": "Unparseable pseudocode snippet with code keywords and multi-line control flow",
|
| 183 |
+
"text": "Here is the raw code snippet:\n```\ndef fix_bounds(grid, x, y):\n if x < 0 or x >= len(grid):\n return False\n if y < 0 or y >= len(grid[0]):\n return False\n return self.check_cell(grid, x, y)\n```"
|
| 184 |
+
},
|
| 185 |
+
{
|
| 186 |
+
"id": "leak_24",
|
| 187 |
+
"expected_leakage": True,
|
| 188 |
+
"description": "Tensor detachment autograd fix in custom trainer",
|
| 189 |
+
"text": "```python\ndef step(self, batch):\n loss = self.model(batch)\n loss.backward()\n self.optimizer.step()\n return loss.detach().cpu().item()\n```"
|
| 190 |
+
},
|
| 191 |
+
{
|
| 192 |
+
"id": "leak_25",
|
| 193 |
+
"expected_leakage": True,
|
| 194 |
+
"description": "Minimax with alpha-beta pruning complete wrapper",
|
| 195 |
+
"text": "```python\ndef get_best_move(board, depth):\n best_val = -float('inf')\n best_move = None\n for move in board.legal_moves():\n val = minimax(board.make_move(move), depth - 1, False)\n if val > best_val:\n best_val, best_move = val, move\n return best_move\n```"
|
| 196 |
+
},
|
| 197 |
+
|
| 198 |
+
# =========================================================================
|
| 199 |
+
# NON-LEAKAGE CASES (Expected: False) - 25 Valid Socratic Pedagogy Examples
|
| 200 |
+
# =========================================================================
|
| 201 |
+
{
|
| 202 |
+
"id": "non_leak_01",
|
| 203 |
+
"expected_leakage": False,
|
| 204 |
+
"description": "Pure Socratic dialogue with questions",
|
| 205 |
+
"text": "What does your priority queue sort on? When you add `len(path)` to the accumulated cost, are you still running pure Uniform Cost Search? Try tracing a tiny graph with 2 paths."
|
| 206 |
+
},
|
| 207 |
+
{
|
| 208 |
+
"id": "non_leak_02",
|
| 209 |
+
"expected_leakage": False,
|
| 210 |
+
"description": "Inline backticks referencing variable names only",
|
| 211 |
+
"text": "Check your cutoff condition: is it `alpha >= beta` or `alpha > beta`? Think about what happens when `alpha` equals `beta`."
|
| 212 |
+
},
|
| 213 |
+
{
|
| 214 |
+
"id": "non_leak_03",
|
| 215 |
+
"expected_leakage": False,
|
| 216 |
+
"description": "Mathematical formula using LaTeX notation",
|
| 217 |
+
"text": "Recall the Bellman equation: $Q(s, a) = r + \\gamma \\max_{a'} Q(s', a')$. Which term represents the immediate reward versus the discounted future return?"
|
| 218 |
+
},
|
| 219 |
+
{
|
| 220 |
+
"id": "non_leak_04",
|
| 221 |
+
"expected_leakage": False,
|
| 222 |
+
"description": "Single-line code fence containing only an equation / expression without functions or loops",
|
| 223 |
+
"text": "Consider the shape of your tensor before the linear layer:\n```\nExpected shape: (batch_size, num_features)\n```\nWhat is your current batch dimension?"
|
| 224 |
+
},
|
| 225 |
+
{
|
| 226 |
+
"id": "non_leak_05",
|
| 227 |
+
"expected_leakage": False,
|
| 228 |
+
"description": "Guided debugging steps in bullet points",
|
| 229 |
+
"text": "Let's debug this step-by-step:\n1. Print the shape of `x` after the convolution.\n2. Calculate the spatial dimensions: $(W - K + 2P)/S + 1$.\n3. Check if your linear layer input features match the flattened output."
|
| 230 |
+
},
|
| 231 |
+
{
|
| 232 |
+
"id": "non_leak_06",
|
| 233 |
+
"expected_leakage": False,
|
| 234 |
+
"description": "Conceptual explanation of vanishing gradients",
|
| 235 |
+
"text": "When you use the sigmoid activation with large initial weights, the pre-activation $z$ becomes very large. What is the derivative of $\\sigma(z)$ when $z > 10$?"
|
| 236 |
+
},
|
| 237 |
+
{
|
| 238 |
+
"id": "non_leak_07",
|
| 239 |
+
"expected_leakage": False,
|
| 240 |
+
"description": "Explaining A* heuristic admissibility without code",
|
| 241 |
+
"text": "For A* to guarantee the optimal path, the heuristic $h(n)$ must be admissible ($h(n) \\le h^*(n)$). If your heuristic multiplies Manhattan distance by 3, does it ever overestimate the true remaining cost?"
|
| 242 |
+
},
|
| 243 |
+
{
|
| 244 |
+
"id": "non_leak_08",
|
| 245 |
+
"expected_leakage": False,
|
| 246 |
+
"description": "Socratic question about Viterbi transition index order",
|
| 247 |
+
"text": "Does $A[i, j]$ represent the transition probability from state $i$ to state $j$, or from $j$ to $i$? Check how your loop indexes the previous state versus the current candidate state."
|
| 248 |
+
},
|
| 249 |
+
{
|
| 250 |
+
"id": "non_leak_09",
|
| 251 |
+
"expected_leakage": False,
|
| 252 |
+
"description": "Guidance on train vs. eval mode in PyTorch",
|
| 253 |
+
"text": "Why do your test predictions change on every forward pass? Does your model contain stochastic layers like `nn.Dropout`? Have you toggled `model.eval()` before running inference?"
|
| 254 |
+
},
|
| 255 |
+
{
|
| 256 |
+
"id": "non_leak_10",
|
| 257 |
+
"expected_leakage": False,
|
| 258 |
+
"description": "Socratic prompt on decision tree weighted entropy",
|
| 259 |
+
"text": "If one child node contains 95 samples and the other child contains only 5 samples, should their impurities contribute equally to the split score? How does sample weighting affect expected information gain?"
|
| 260 |
+
},
|
| 261 |
+
{
|
| 262 |
+
"id": "non_leak_11",
|
| 263 |
+
"expected_leakage": False,
|
| 264 |
+
"description": "Question on CrossEntropyLoss logits vs. softmax",
|
| 265 |
+
"text": "PyTorch's `nn.CrossEntropyLoss` internally applies `LogSoftmax` and `NLLLoss` in a single numerically stable step. What happens if you pass already-softmaxed probabilities into it?"
|
| 266 |
+
},
|
| 267 |
+
{
|
| 268 |
+
"id": "non_leak_12",
|
| 269 |
+
"expected_leakage": False,
|
| 270 |
+
"description": "Short code fence with 1-line mathematical formula",
|
| 271 |
+
"text": "Remember the update formula:\n```\nTD Target = R + gamma * max_a Q(S', a)\n```\nWhich term is multiplied by gamma?"
|
| 272 |
+
},
|
| 273 |
+
{
|
| 274 |
+
"id": "non_leak_13",
|
| 275 |
+
"expected_leakage": False,
|
| 276 |
+
"description": "Guided trace exercise for graph search",
|
| 277 |
+
"text": "Try tracing a simple 3-node cycle: $A \\to B \\to C \\to A$. If node $B$ is popped, when should its neighbors be added to the visited set?"
|
| 278 |
+
},
|
| 279 |
+
{
|
| 280 |
+
"id": "non_leak_14",
|
| 281 |
+
"expected_leakage": False,
|
| 282 |
+
"description": "Explanation of data leakage in preprocessing",
|
| 283 |
+
"text": "When you fit `StandardScaler` on the whole dataset before splitting into train and test sets, what information from the test set leaks into the mean and standard deviation?"
|
| 284 |
+
},
|
| 285 |
+
{
|
| 286 |
+
"id": "non_leak_15",
|
| 287 |
+
"expected_leakage": False,
|
| 288 |
+
"description": "Socratic question on epsilon decay schedule",
|
| 289 |
+
"text": "If $\\epsilon = 1.0$ and you subtract 0.9 on the first episode, what is your exploration rate on episode 2? Did you intend linear subtraction or multiplicative decay?"
|
| 290 |
+
},
|
| 291 |
+
{
|
| 292 |
+
"id": "non_leak_16",
|
| 293 |
+
"expected_leakage": False,
|
| 294 |
+
"description": "Clarifying terminal state masking in RL",
|
| 295 |
+
"text": "When an episode terminates (`done = True`), is there any future state to transition to? What should the bootstrapped value $\\max Q(s', a')$ evaluate to at a terminal boundary?"
|
| 296 |
+
},
|
| 297 |
+
{
|
| 298 |
+
"id": "non_leak_17",
|
| 299 |
+
"expected_leakage": False,
|
| 300 |
+
"description": "Explaining zero-frequency problem in Naive Bayes",
|
| 301 |
+
"text": "If a word never appears in the training examples for class $C$, what is $P(w | C)$ without smoothing? What happens when you multiply several probabilities and one of them is zero?"
|
| 302 |
+
},
|
| 303 |
+
{
|
| 304 |
+
"id": "non_leak_18",
|
| 305 |
+
"expected_leakage": False,
|
| 306 |
+
"description": "Code snippet showing only student's error message",
|
| 307 |
+
"text": "Notice the error you received:\n```\nRuntimeError: Expected size [12, 10] but got [1, 120]\n```\nWhy did the batch size of 12 get collapsed into 1?"
|
| 308 |
+
},
|
| 309 |
+
{
|
| 310 |
+
"id": "non_leak_19",
|
| 311 |
+
"expected_leakage": False,
|
| 312 |
+
"description": "Discussion of L1 vs L2 regularization shrinkage",
|
| 313 |
+
"text": "How does L1 regularization differ from L2 regularization in terms of weight sparsity? Why does the derivative of $|w|$ produce exact zeros while $w^2$ shrinks weights proportionally?"
|
| 314 |
+
},
|
| 315 |
+
{
|
| 316 |
+
"id": "non_leak_20",
|
| 317 |
+
"expected_leakage": False,
|
| 318 |
+
"description": "Socratic questioning on Bayesian network d-separation",
|
| 319 |
+
"text": "In the collider structure $A \\to C \\leftarrow B$, are $A$ and $B$ marginally independent? What happens to the active path between $A$ and $B$ once you condition on $C$?"
|
| 320 |
+
},
|
| 321 |
+
{
|
| 322 |
+
"id": "non_leak_21",
|
| 323 |
+
"expected_leakage": False,
|
| 324 |
+
"description": "Guided inquiry on gradient accumulation resetting",
|
| 325 |
+
"text": "In PyTorch, `loss.backward()` accumulates gradients into `.grad` buffers rather than overwriting them. Where in your mini-batch loop should you invoke `optimizer.zero_grad()`?"
|
| 326 |
+
},
|
| 327 |
+
{
|
| 328 |
+
"id": "non_leak_22",
|
| 329 |
+
"expected_leakage": False,
|
| 330 |
+
"description": "Explaining difference between BFS and DFS queue structures",
|
| 331 |
+
"text": "BFS explores nodes level-by-level using a FIFO queue (`collections.deque`), whereas DFS uses a LIFO stack. Why does a FIFO queue guarantee the shortest path on unweighted graphs?"
|
| 332 |
+
},
|
| 333 |
+
{
|
| 334 |
+
"id": "non_leak_23",
|
| 335 |
+
"expected_leakage": False,
|
| 336 |
+
"description": "Reflective question on loss reduction averaging",
|
| 337 |
+
"text": "If you use `reduction='sum'`, does the loss scale with the number of samples in the mini-batch? How does that affect your effective learning rate when batch sizes vary?"
|
| 338 |
+
},
|
| 339 |
+
{
|
| 340 |
+
"id": "non_leak_24",
|
| 341 |
+
"expected_leakage": False,
|
| 342 |
+
"description": "Minimax sign convention explanation",
|
| 343 |
+
"text": "If `state.evaluate()` returns positive values when Player 1 is winning, how should the minimizing player (Player 2) evaluate child nodes? Are you negating the score consistently at each ply?"
|
| 344 |
+
},
|
| 345 |
+
{
|
| 346 |
+
"id": "non_leak_25",
|
| 347 |
+
"expected_leakage": False,
|
| 348 |
+
"description": "Prompting student to inspect learning rate magnitude",
|
| 349 |
+
"text": "If your network weights explode to `inf` within 3 iterations, check the scale of your learning rate. Try reducing $\\alpha$ from $10.0$ to $0.001$ and inspect the gradient norms."
|
| 350 |
+
}
|
| 351 |
+
]
|
| 352 |
+
|
| 353 |
+
|
| 354 |
+
# ---------------------------------------------------------------------------
|
| 355 |
+
# Benchmark Execution and Metric Computation
|
| 356 |
+
# ---------------------------------------------------------------------------
|
| 357 |
+
def run_benchmark():
|
| 358 |
+
print("=" * 80)
|
| 359 |
+
print(" DETERMINISTIC AST CODE LEAKAGE VERIFIER BENCHMARK (50 Ground-Truth Cases)")
|
| 360 |
+
print("=" * 80)
|
| 361 |
+
|
| 362 |
+
tp = 0 # True Positives: Predicted Leakage, Actual Leakage
|
| 363 |
+
tn = 0 # True Negatives: Predicted No Leakage, Actual No Leakage
|
| 364 |
+
fp = 0 # False Positives: Predicted Leakage, Actual No Leakage
|
| 365 |
+
fn = 0 # False Negatives: Predicted No Leakage, Actual Leakage
|
| 366 |
+
|
| 367 |
+
results_log = []
|
| 368 |
+
|
| 369 |
+
for item in TEST_SUITE:
|
| 370 |
+
predicted = detect_ast_code_leakage(item["text"])
|
| 371 |
+
expected = item["expected_leakage"]
|
| 372 |
+
is_correct = (predicted == expected)
|
| 373 |
+
|
| 374 |
+
if expected and predicted:
|
| 375 |
+
tp += 1
|
| 376 |
+
status = "[PASS] TRUE POSITIVE"
|
| 377 |
+
elif not expected and not predicted:
|
| 378 |
+
tn += 1
|
| 379 |
+
status = "[PASS] TRUE NEGATIVE"
|
| 380 |
+
elif not expected and predicted:
|
| 381 |
+
fp += 1
|
| 382 |
+
status = "[FAIL] FALSE POSITIVE (Over-flagged)"
|
| 383 |
+
else:
|
| 384 |
+
fn += 1
|
| 385 |
+
status = "[FAIL] FALSE NEGATIVE (Missed leak)"
|
| 386 |
+
|
| 387 |
+
results_log.append({
|
| 388 |
+
"id": item["id"],
|
| 389 |
+
"description": item["description"],
|
| 390 |
+
"expected_leakage": expected,
|
| 391 |
+
"predicted_leakage": predicted,
|
| 392 |
+
"status": status,
|
| 393 |
+
"sample_snippet": item["text"][:120] + "..." if len(item["text"]) > 120 else item["text"]
|
| 394 |
+
})
|
| 395 |
+
|
| 396 |
+
print(f"[{item['id']}] Expected: {str(expected):<5} | Predicted: {str(predicted):<5} | {status:<30} | {item['description']}")
|
| 397 |
+
|
| 398 |
+
# Metric calculations
|
| 399 |
+
total = len(TEST_SUITE)
|
| 400 |
+
accuracy = ((tp + tn) / total) * 100.0
|
| 401 |
+
precision = (tp / (tp + fp) * 100.0) if (tp + fp) > 0 else 0.0
|
| 402 |
+
recall = (tp / (tp + fn) * 100.0) if (tp + fn) > 0 else 0.0
|
| 403 |
+
f1 = (2 * precision * recall / (precision + recall)) if (precision + recall) > 0 else 0.0
|
| 404 |
+
|
| 405 |
+
print("\n" + "=" * 80)
|
| 406 |
+
print(" [SUMMARY] AST CODE LEAKAGE VERIFIER PERFORMANCE")
|
| 407 |
+
print("=" * 80)
|
| 408 |
+
print(f" Total Benchmark Test Cases : {total}")
|
| 409 |
+
print(f" True Positives (TP) : {tp} / 25")
|
| 410 |
+
print(f" True Negatives (TN) : {tn} / 25")
|
| 411 |
+
print(f" False Positives (FP) : {fp} / 25")
|
| 412 |
+
print(f" False Negatives (FN) : {fn} / 25")
|
| 413 |
+
print("-" * 80)
|
| 414 |
+
print(f" Classification Accuracy : {accuracy:.2f}%")
|
| 415 |
+
print(f" Precision : {precision:.2f}%")
|
| 416 |
+
print(f" Recall : {recall:.2f}%")
|
| 417 |
+
print(f" F1 Score : {f1:.2f}%")
|
| 418 |
+
print("=" * 80)
|
| 419 |
+
|
| 420 |
+
# Save benchmark results to JSON
|
| 421 |
+
benchmark_data = {
|
| 422 |
+
"metrics": {
|
| 423 |
+
"total_cases": total,
|
| 424 |
+
"true_positives": tp,
|
| 425 |
+
"true_negatives": tn,
|
| 426 |
+
"false_positives": fp,
|
| 427 |
+
"false_negatives": fn,
|
| 428 |
+
"accuracy_pct": accuracy,
|
| 429 |
+
"precision_pct": precision,
|
| 430 |
+
"recall_pct": recall,
|
| 431 |
+
"f1_score": f1
|
| 432 |
+
},
|
| 433 |
+
"test_cases": results_log
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
with open("ast_verifier_benchmark_50.json", "w", encoding="utf-8") as f:
|
| 437 |
+
json.dump(benchmark_data, f, indent=2)
|
| 438 |
+
|
| 439 |
+
print("\n[+] Benchmark test results exported to 'ast_verifier_benchmark_50.json'")
|
| 440 |
+
|
| 441 |
+
if __name__ == "__main__":
|
| 442 |
+
run_benchmark()
|