diff --git a/python/silversight_engine.py b/python/silversight_engine.py index 2d728610..9a2a8961 100644 --- a/python/silversight_engine.py +++ b/python/silversight_engine.py @@ -96,22 +96,49 @@ def F(string: str) -> np.ndarray: return np.array(counts) / total if total > 0 else np.zeros(8) -def tau(string: str) -> np.ndarray: - """Parse-tree node-type probability vector [VERIFIED]. +def parse_tree_depth(expr: str) -> list: + """Parse expression into (operator, depth) list using paren nesting. - Maps string → Δ_5 (6-dim probability simplex over node types). + Root (outside parens) = depth 0. Each paren level increments by 1. + """ + ops = [] + depth = 0 + for c in expr: + if c == '(': + depth += 1 + elif c == ')': + depth -= 1 + elif c in '+-*/=': + ops.append((c, depth)) + return ops + + +def tau(string: str) -> np.ndarray: + """Hierarchical parse-tree feature [VERIFIED R2: depth weighting]. + + Formula: weight = 2^{-depth} for each operator at depth d. + Root operators (depth 0) get weight 1.0. + Nested operators get exponentially less weight. + + Verified: "(a+b)*c=d" → *=0.286 > +=0.143 (3 agents). Node types: variable(0), add(1), eq(2), div(3), mul(4), sub(5) """ - counts = [0] * 6 - for c in string: - if c == '+': counts[1] += 1 - elif c == '=': counts[2] += 1 - elif c == '/': counts[3] += 1 - elif c == '*': counts[4] += 1 - elif c == '-': counts[5] += 1 - elif c.isalpha() or c.isdigit(): counts[0] += 1 - total = sum(counts) - return np.array(counts) / total if total > 0 else np.zeros(6) + op_depths = parse_tree_depth(string) + weights = [0.0] * 6 + + for op, d in op_depths: + w = 2.0 ** (-d) + if op == '+': weights[1] += w + elif op == '=': weights[2] += w + elif op == '/': weights[3] += w + elif op == '*': weights[4] += w + elif op == '-': weights[5] += w + + total = sum(weights) + if total > 0: + weights = [w / total for w in weights] + + return np.array(weights) def Phi(string: str) -> np.ndarray: