GUIDO_test_200M / vathos /complexity.py
Paerle's picture
Initial upload: GUIDO-small 200M bugfix ckpt + Vathos + modeling + README
d8c733f verified
Raw
History Blame Contribute Delete
7.01 kB
import re
from collections import defaultdict
from typing import List, Tuple, Dict
def parse_complexity(complexity: str) -> Tuple[Dict[str, int], List[str]]:
"""
Parse a Big O complexity string.
Returns:
Tuple of (variable_exponents dict, log_terms list)
where log_terms contains the variables inside log (e.g., ['n', 'L'])
"""
match = re.search(r'O\((.*?)\)', complexity)
if not match:
return {}, []
content = match.group(1).strip()
log_terms = []
log_matches = re.findall(r'\blog\s+(\w+)', content, flags=re.IGNORECASE)
log_terms.extend(log_matches)
standalone_logs = re.findall(r'\blog(?!\s+\w)', content, flags=re.IGNORECASE)
log_terms.extend(['n'] * len(standalone_logs))
content_no_log = re.sub(r'\blog\s*\w*', '', content, flags=re.IGNORECASE)
exponents = defaultdict(int)
tokens = re.findall(r'([a-zA-Z_]\w*)(?:\^(\d+))?', content_no_log)
for var, exp in tokens:
if var and var.lower() != 'log':
exponent = int(exp) if exp else 1
exponents[var] = max(exponents[var], exponent)
return dict(exponents), log_terms
def compare_complexities(c1: Tuple[Dict[str, int], List[str]],
c2: Tuple[Dict[str, int], List[str]]) -> int:
"""
Compare two complexities.
Returns: 1 if c1 > c2, -1 if c1 < c2, 0 if equal
"""
exp1, log1 = c1
exp2, log2 = c2
all_vars = set(exp1.keys()) | set(exp2.keys())
for var in sorted(all_vars):
e1 = exp1.get(var, 0)
e2 = exp2.get(var, 0)
if e1 > e2:
return 1
elif e1 < e2:
return -1
if len(log1) > len(log2):
return 1
elif len(log1) < len(log2):
return -1
return 0
def combine_big_o_product(complexities: List[str]) -> str:
"""
Combines multiple Big O complexity strings by taking the dominant complexity.
Args:
complexities: List of Big O notation strings
Returns:
Combined Big O notation representing the dominant complexity
Examples:
>>> combine_big_o(["O(n^2)", "O(n log n)", "O(n^3)"])
'O(n^3)'
>>> combine_big_o(["O(n)", "O(n log n)"])
'O(n log n)'
>>> combine_big_o(["O(L^2 d^2)", "O(L d^2 k)", "O(L^2 d^2)"])
'O(L^2 d^2 k)'
"""
if not complexities:
return "O(1)"
parsed = [parse_complexity(c) for c in complexities]
# Find the dominant complexity
dominant = parsed[0]
dominant_str = complexities[0]
for i in range(1, len(parsed)):
if compare_complexities(parsed[i], dominant) > 0:
dominant = parsed[i]
dominant_str = complexities[i]
# Find the maximum exponents for all variables
max_exponents = defaultdict(int)
for exponents, log_terms in parsed:
for var, exp in exponents.items():
max_exponents[var] = max(max_exponents[var], exp)
# Collect all log terms from complexities with maximum polynomial degree
all_log_terms = []
for exponents, log_terms in parsed:
has_max_degree = True
# Check if this has any variable at less than max exponent
for var, exp in exponents.items():
if exp < max_exponents[var]:
has_max_degree = False
break
# If it has max degree for its variables, keep its log terms
if has_max_degree:
all_log_terms.extend(log_terms)
if not max_exponents and not all_log_terms:
return "O(1)"
# Build the result string
terms = []
# Add variable terms
for var in sorted(max_exponents.keys()):
exp = max_exponents[var]
if exp == 1:
terms.append(var)
else:
terms.append(f"{var}^{exp}")
# Add log terms if applicable
if all_log_terms:
log_str = " ".join([f"log {var}" for var in sorted(set(all_log_terms))])
if terms:
terms.append(log_str)
else:
return f"O({log_str})"
return f"O({' '.join(terms)})"
from typing import List
from collections import defaultdict
import re
def combine_big_o_sum(complexities: List[str]) -> str:
"""
Combines multiple Big O complexity strings by summing them and simplifying
like terms to return a human-readable dominant complexity.
Args:
complexities: List of Big O notation strings
Returns:
Combined Big O notation representing the simplified sum
Examples:
>>> combine_big_o_sum(["O(n^2)", "O(n)", "O(1)"])
'O(n^2)'
>>> combine_big_o_sum(["O(L d^2)", "O(L d^2)", "O(L^2 d)"])
'O(L d^2 + L^2 d)'
>>> combine_big_o_sum(["O(depth L d^2)", "O(L^2 d)", "O(L d^2)", "O(L d^2)", "O(L d)"])
'O(L d^2 + L^2 d)'
"""
if not complexities:
return "O(1)"
all_terms = []
for c in complexities:
term = c.strip()
if term.startswith("O(") and term.endswith(")"):
term = term[2:-1].strip()
if term and term != "1":
# Split by + to handle multiple terms in one complexity
all_terms.extend([t.strip() for t in term.split('+')])
if not all_terms:
return "O(1)"
term_groups = defaultdict(list)
for term in all_terms:
var_signature = []
parts = term.split()
for part in parts:
if part.replace('.', '').isdigit() or part in ['depth', 'batch', 'const']:
continue
# Parse variable with optional exponent
if '^' in part:
var, exp = part.split('^')
var_signature.append((var, int(exp)))
else:
var_signature.append((part, 1))
# Sort to create canonical signature
var_signature = tuple(sorted(var_signature))
term_groups[var_signature].append(term)
unique_terms = []
for sig, terms in term_groups.items():
representative = min(terms, key=lambda t: (len(t), t))
unique_terms.append((sig, representative))
if not unique_terms:
return "O(1)"
def complexity_score(sig_term):
sig, term = sig_term
if not sig:
return (0, 0, term)
# Total degree and max degree
total_degree = sum(exp for var, exp in sig)
max_degree = max(exp for var, exp in sig)
return (max_degree, total_degree, term)
unique_terms.sort(key=complexity_score, reverse=True)
# If clearly dominated, return just the dominant term(s)
if len(unique_terms) > 1:
top_score = complexity_score(unique_terms[0])
# Keep all terms with the same max complexity
result_terms = [term for sig_term in unique_terms
if complexity_score(sig_term)[0] == top_score[0]]
else:
result_terms = [unique_terms[0][1]]
# Build result
if len(result_terms) == 1:
return f"O({result_terms[0]})"
else:
return f"O({' + '.join(result_terms)})"