Plot2Eq / src /plot2eq /data_prep /canonicalize.py
YauheniShe's picture
Изменил структуру проекта
559e904
Raw History Blame Contribute Delete
3.45 kB
import gzip
import pickle
from pathlib import Path
import sympy as sp
from sympy.core.cache import clear_cache
from tqdm import tqdm
from plot2eq.core.tokenizer import InvalidExpressionError, Tokenizer
def get_c_node():
return sp.Symbol("C", real=True)
def has_top_level_shift(expr: sp.Expr) -> bool:
if expr.is_Symbol and str(expr).startswith("C"):
return True
if expr.is_Add:
for arg in expr.args:
if has_top_level_shift(arg): # type: ignore
return True
return False
def replace_cos_unevaluated(expr):
if not expr.args:
return expr
new_args = [replace_cos_unevaluated(arg) for arg in expr.args]
current_func = expr.func
new_func = sp.sin if current_func == sp.cos else current_func
return new_func(*new_args, evaluate=False)
def clean_item(item, tokenizer: Tokenizer):
try:
tokens = item["tokens"]
expr = tokenizer.token_seq_to_expr(tokens)
if expr.has(sp.sin) and expr.has(sp.cos):
return None
processed_expr = replace_cos_unevaluated(expr) if expr.has(sp.cos) else expr
if not has_top_level_shift(processed_expr):
processed_expr = sp.Add(processed_expr, get_c_node(), evaluate=False)
clear_expr = tokenizer.canonicalize_tree_structure(processed_expr)
new_tokens = tokenizer.expr_to_token_seq(clear_expr)
return {
"expr_str": str(clear_expr),
"expr_instantiated_str": item["expr_instantiated_str"],
"tokens": new_tokens,
"points": item["points"],
}
except InvalidExpressionError:
return None
def run_canonicalization(input_dir: Path, output_dir: Path, chunk_size: int = 50000):
output_dir.mkdir(parents=True, exist_ok=True)
tokenizer = Tokenizer()
input_files = sorted(input_dir.glob("chunk_*.pkl.gz"))
if not input_files:
print("В папке не найдено чанков для обработки.")
return
cleaned_buffer = []
new_chunk_index = 0
total_processed, total_skipped = 0, 0
operations_count = 0
print(f"Найдено {len(input_files)} чанков. Начинаю канонизацию формул...")
for filepath in tqdm(input_files, desc="Канонизация"):
with gzip.open(filepath, "rb") as f:
data = pickle.load(f)
for item in data:
operations_count += 1
if operations_count % 10000 == 0:
clear_cache()
cleaned = clean_item(item, tokenizer)
if cleaned:
cleaned_buffer.append(cleaned)
else:
total_skipped += 1
if len(cleaned_buffer) >= chunk_size:
savepath = output_dir / f"chunk_{new_chunk_index}.pkl.gz"
with gzip.open(savepath, "wb") as f_out:
pickle.dump(cleaned_buffer[:chunk_size], f_out)
total_processed += chunk_size
cleaned_buffer = cleaned_buffer[chunk_size:]
new_chunk_index += 1
if cleaned_buffer:
savepath = output_dir / f"chunk_{new_chunk_index}.pkl.gz"
with gzip.open(savepath, "wb") as f_out:
pickle.dump(cleaned_buffer, f_out)
total_processed += len(cleaned_buffer)
print(f"Успешно очищено: {total_processed}. Пропущено ошибок: {total_skipped}.")