Цвета в табличках, остановка по лучшему решению
This commit is contained in:
@@ -12,12 +12,16 @@
|
||||
- "—" для отсутствующих данных
|
||||
|
||||
Выходной файл: tables.tex с готовым LaTeX кодом всех таблиц.
|
||||
Лучший результат по времени выполнения в каждой таблице выделяется жирным.
|
||||
Лучшие результаты по времени и фитнесу выделяются жирным (и цветом, если задан HIGHLIGHT_COLOR).
|
||||
"""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
# Настройка цвета для выделения лучших результатов
|
||||
# None - только жирным, строка (например "magenta") - жирным и цветом
|
||||
HIGHLIGHT_COLOR = "magenta"
|
||||
|
||||
|
||||
def parse_csv_file(csv_path: str) -> tuple[str, list[list[str]]]:
|
||||
"""
|
||||
@@ -53,7 +57,7 @@ def parse_csv_file(csv_path: str) -> tuple[str, list[list[str]]]:
|
||||
|
||||
def extract_time_value(value: str) -> float | None:
|
||||
"""
|
||||
Извлекает значение времени из строки формата "X.Y (Z)".
|
||||
Извлекает значение времени из строки формата "X.Y (Z)" или "X.Y (Z) W.V".
|
||||
|
||||
Args:
|
||||
value: Строка с результатом
|
||||
@@ -73,6 +77,29 @@ def extract_time_value(value: str) -> float | None:
|
||||
return None
|
||||
|
||||
|
||||
def extract_fitness_value(value: str) -> float | None:
|
||||
"""
|
||||
Извлекает значение фитнеса из строки формата "X.Y (Z) W.V".
|
||||
|
||||
Args:
|
||||
value: Строка с результатом
|
||||
|
||||
Returns:
|
||||
Значение фитнеса как float или None если значение пустое
|
||||
"""
|
||||
value = value.strip()
|
||||
if value == "—" or value == "" or value == "–":
|
||||
return None
|
||||
|
||||
# Ищем паттерн "число.число (число) число.число"
|
||||
# Фитнес - это последнее число в строке
|
||||
match = re.search(r"\)\s+(\d+\.?\d*)\s*$", value)
|
||||
if match:
|
||||
return float(match.group(1))
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def find_best_time(data_rows: list[list[str]]) -> float | None:
|
||||
"""
|
||||
Находит минимальное время выполнения среди всех значений в таблице.
|
||||
@@ -95,13 +122,38 @@ def find_best_time(data_rows: list[list[str]]) -> float | None:
|
||||
return min_time
|
||||
|
||||
|
||||
def format_value(value: str, best_time: float | None = None) -> str:
|
||||
def find_best_fitness(data_rows: list[list[str]]) -> float | None:
|
||||
"""
|
||||
Форматирует значение для LaTeX таблицы, выделяя лучший результат жирным.
|
||||
Находит минимальное значение фитнеса среди всех значений в таблице.
|
||||
|
||||
Args:
|
||||
data_rows: Строки данных таблицы
|
||||
|
||||
Returns:
|
||||
Минимальное значение фитнеса или None если нет валидных значений
|
||||
"""
|
||||
min_fitness = None
|
||||
|
||||
for row in data_rows:
|
||||
for i in range(1, min(6, len(row))): # Пропускаем первую колонку (Pc)
|
||||
fitness_value = extract_fitness_value(row[i])
|
||||
if fitness_value is not None:
|
||||
if min_fitness is None or fitness_value < min_fitness:
|
||||
min_fitness = fitness_value
|
||||
|
||||
return min_fitness
|
||||
|
||||
|
||||
def format_value(
|
||||
value: str, best_time: float | None = None, best_fitness: float | None = None
|
||||
) -> str:
|
||||
"""
|
||||
Форматирует значение для LaTeX таблицы, выделяя лучшие результаты жирным.
|
||||
|
||||
Args:
|
||||
value: Строковое значение из CSV
|
||||
best_time: Лучшее время в таблице для сравнения
|
||||
best_fitness: Лучший фитнес в таблице для сравнения
|
||||
|
||||
Returns:
|
||||
Отформатированное значение для LaTeX
|
||||
@@ -110,16 +162,52 @@ def format_value(value: str, best_time: float | None = None) -> str:
|
||||
if value == "—" or value == "" or value == "–":
|
||||
return "—"
|
||||
|
||||
# Проверяем, является ли это лучшим результатом
|
||||
current_time = extract_time_value(value)
|
||||
if (
|
||||
current_time is not None
|
||||
and best_time is not None
|
||||
and abs(current_time - best_time) < 0.001
|
||||
):
|
||||
return f"\\textbf{{{value}}}"
|
||||
# Проверяем есть ли фитнес в строке
|
||||
fitness_match = re.search(r"(\d+\.?\d*)\s*\((\d+)\)\s+(\d+\.?\d*)\s*$", value)
|
||||
|
||||
return value
|
||||
if fitness_match:
|
||||
# Есть фитнес: "время (поколения) фитнес"
|
||||
time_str = fitness_match.group(1)
|
||||
generations_str = fitness_match.group(2)
|
||||
fitness_str = fitness_match.group(3)
|
||||
|
||||
current_time = float(time_str)
|
||||
current_fitness = float(fitness_str)
|
||||
|
||||
# Проверяем, является ли время лучшим
|
||||
time_part = f"{time_str} ({generations_str})"
|
||||
if best_time is not None and abs(current_time - best_time) < 0.001:
|
||||
if HIGHLIGHT_COLOR is not None:
|
||||
time_part = (
|
||||
f"\\textcolor{{{HIGHLIGHT_COLOR}}}{{\\textbf{{{time_part}}}}}"
|
||||
)
|
||||
else:
|
||||
time_part = f"\\textbf{{{time_part}}}"
|
||||
|
||||
# Проверяем, является ли фитнес лучшим
|
||||
fitness_part = fitness_str
|
||||
if best_fitness is not None and abs(current_fitness - best_fitness) < 0.00001:
|
||||
if HIGHLIGHT_COLOR is not None:
|
||||
fitness_part = (
|
||||
f"\\textcolor{{{HIGHLIGHT_COLOR}}}{{\\textbf{{{fitness_part}}}}}"
|
||||
)
|
||||
else:
|
||||
fitness_part = f"\\textbf{{{fitness_part}}}"
|
||||
|
||||
return f"{time_part} {fitness_part}"
|
||||
|
||||
else:
|
||||
# Нет фитнеса: только "время (поколения)"
|
||||
time_match = re.match(r"(\d+\.?\d*)\s*\((\d+)\)", value)
|
||||
if time_match:
|
||||
current_time = float(time_match.group(1))
|
||||
if best_time is not None and abs(current_time - best_time) < 0.001:
|
||||
if HIGHLIGHT_COLOR is not None:
|
||||
return f"\\textcolor{{{HIGHLIGHT_COLOR}}}{{\\textbf{{{value}}}}}"
|
||||
else:
|
||||
return f"\\textbf{{{value}}}"
|
||||
|
||||
return value
|
||||
|
||||
|
||||
def generate_latex_table(n: str, header: str, data_rows: list[list[str]]) -> str:
|
||||
@@ -134,8 +222,9 @@ def generate_latex_table(n: str, header: str, data_rows: list[list[str]]) -> str
|
||||
Returns:
|
||||
LaTeX код таблицы
|
||||
"""
|
||||
# Находим лучшее время в таблице
|
||||
# Находим лучшее время и лучший фитнес в таблице
|
||||
best_time = find_best_time(data_rows)
|
||||
best_fitness = find_best_fitness(data_rows)
|
||||
|
||||
# Извлекаем заголовки колонок из header
|
||||
header_parts = header.split(",")
|
||||
@@ -162,7 +251,7 @@ def generate_latex_table(n: str, header: str, data_rows: list[list[str]]) -> str
|
||||
|
||||
# Добавляем значения для каждого Pm
|
||||
for i in range(1, min(6, len(row))): # Максимум 5 колонок Pm
|
||||
value = format_value(row[i], best_time)
|
||||
value = format_value(row[i], best_time, best_fitness)
|
||||
latex_code += f" & {value}"
|
||||
|
||||
# Заполняем недостающие колонки если их меньше 5
|
||||
@@ -207,9 +296,12 @@ def main():
|
||||
try:
|
||||
header, data_rows = parse_csv_file(str(csv_file))
|
||||
best_time = find_best_time(data_rows)
|
||||
best_fitness = find_best_fitness(data_rows)
|
||||
latex_table = generate_latex_table(n, header, data_rows)
|
||||
tables.append(latex_table)
|
||||
print(f"✓ Таблица для N={n} готова (лучшее время: {best_time})")
|
||||
print(
|
||||
f"✓ Таблица для N={n} готова (лучшее время: {best_time}, лучший фитнес: {best_fitness})"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Ошибка при обработке {csv_file}: {e}")
|
||||
@@ -221,9 +313,13 @@ def main():
|
||||
with open("tables.tex", "w", encoding="utf-8") as f:
|
||||
f.write("% Автоматически сгенерированные LaTeX таблицы\n")
|
||||
f.write(
|
||||
"% Лучший результат по времени выполнения в каждой таблице выделен жирным\n"
|
||||
"% Лучший результат по времени и по фитнесу выделены жирным отдельно\n"
|
||||
)
|
||||
f.write("% Убедитесь, что подключен \\usepackage{tabularx}\n")
|
||||
if HIGHLIGHT_COLOR is not None:
|
||||
f.write(
|
||||
"% ВНИМАНИЕ: Убедитесь, что подключен \\usepackage{xcolor} для цветового выделения\n"
|
||||
)
|
||||
f.write(
|
||||
"% Используйте \\newcolumntype{Y}{>{\\centering\\arraybackslash}X} перед таблицами\n\n"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user