Skip to content

Commit 0851fc5

Browse files
committed
Support kotgll evaluation
1 parent 814ab7f commit 0851fc5

File tree

3 files changed

+124
-1
lines changed

3 files changed

+124
-1
lines changed

Dockerfile-all-tools

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ RUN sed -i 's|/home/aftab/Downloads/boost_1_62_installed|'$BOOST_ROOT'|g' /grasp
6464
RUN cd /graspan/src && make
6565
ENV GRASPAN_DIR=/graspan
6666

67+
# kotgll (general-purpose CFL-r tool)
68+
RUN apt-get update && apt-get install -y curl
69+
RUN mkdir -p /kotgll
70+
RUN curl -L -O https://github.com/vadyushkins/kotgll/releases/download/v1.0.8/kotgll-1.0.8.jar \
71+
&& mv kotgll-1.0.8.jar /kotgll/kotgll.jar
72+
ENV KOTGLL_DIR=/kotgll
73+
6774
# CFPQ_PyAlgo dependencies
6875
RUN apt-get update && apt-get install -y \
6976
software-properties-common \

cfpq_eval/runners/all_pairs_cflr_tool_runner_facade.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
GigascaleAllPairsCflrToolRunner)
77
from cfpq_eval.runners.graspan_algo_all_pairs_cflr_tool_runner import (
88
GraspanAllPairsCflrToolRunner)
9+
from cfpq_eval.runners.kotgll_all_pairs_cflr_tool_runner import (
10+
KotgllAllPairsCflrToolRunner)
911
from cfpq_eval.runners.pearl_algo_all_pairs_cflr_tool_runner import (
1012
PearlAllPairsCflrToolRunner)
1113
from cfpq_eval.runners.pocr_algo_all_pairs_cflr_tool_runner import (
@@ -24,7 +26,8 @@ def run_appropriate_all_pairs_cflr_tool(
2426
"pocr": PocrAllPairsCflrToolRunner,
2527
"pearl": PearlAllPairsCflrToolRunner,
2628
"gigascale": GigascaleAllPairsCflrToolRunner,
27-
"graspan": GraspanAllPairsCflrToolRunner
29+
"graspan": GraspanAllPairsCflrToolRunner,
30+
"kotgll": KotgllAllPairsCflrToolRunner,
2831
}.get(algo_settings, PyAlgoAllPairsCflrToolRunner)(
2932
algo_settings, graph_path, grammar_path, timeout_sec
3033
).run()
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import os
2+
import subprocess
3+
import uuid
4+
import warnings
5+
from pathlib import Path
6+
from typing import Optional
7+
8+
import pandas as pd
9+
import psutil
10+
11+
from cfpq_eval.runners.all_pairs_cflr_tool_runner import (
12+
AbstractAllPairsCflrToolRunner,
13+
CflrToolRunResult
14+
)
15+
from cfpq_model.cnf_grammar_template import CnfGrammarTemplate
16+
from cfpq_model.label_decomposed_graph import LabelDecomposedGraph
17+
from cfpq_model.model_utils import explode_indices
18+
19+
20+
class KotgllAllPairsCflrToolRunner(AbstractAllPairsCflrToolRunner):
21+
@property
22+
def base_command(self) -> Optional[str]:
23+
grammar = CnfGrammarTemplate.read_from_pocr_cnf_file(self.grammar_path)
24+
graph = LabelDecomposedGraph.read_from_pocr_graph_file(self.graph_path)
25+
26+
grammar_path = self.grammar_path.parent / "kotgll" / (self.grammar_path.stem + ".rsm")
27+
if not os.path.isfile(grammar_path):
28+
grammar_path = grammar_path.with_suffix(".cfg")
29+
if not os.path.isfile(grammar_path):
30+
warnings.warn(
31+
"Skipping kotgll evaluation, because RSM/CFG is missing. "
32+
"To fix this error write RSM/CFG to "
33+
f"'{grammar_path.with_suffix('.rsm')}' or '{grammar_path.with_suffix('.cfg')}'. "
34+
"See https://github.com/vadyushkins/kotgll?tab=readme-ov-file#rsm-format-example"
35+
)
36+
return None
37+
if graph.block_matrix_space.block_count > 1:
38+
exploded_grammar_path = (
39+
self.grammar_path.parent / "kotgll" / self.grammar_path.stem /
40+
self.graph_path.stem / (self.grammar_path.stem + grammar_path.suffix)
41+
)
42+
self._explode_grammar(
43+
grammar_path,
44+
exploded_grammar_path,
45+
graph.block_matrix_space.block_count
46+
)
47+
grammar_path = exploded_grammar_path
48+
49+
# kotgll doesn't support indexed symbols, we need to concat labels and indices
50+
graph, grammar = explode_indices(graph, grammar)
51+
graph_path = self.graph_path.parent / "kotgll" / self.graph_path.stem / self.graph_path.name
52+
os.makedirs(graph_path.parent, exist_ok=True)
53+
# kotgll requires its own graph formatting, so we need to save the graph in a custom format
54+
self._write_kotgll_graph(graph, graph_path)
55+
56+
out_folder = self.graph_path.parent / "kotgll" / 'out' / str(uuid.uuid4())
57+
os.makedirs(out_folder)
58+
59+
return (
60+
f'java -Xmx{self._get_max_memory_gb()}G '
61+
'-cp kotgll.jar org.kotgll.benchmarks.BenchmarksKt '
62+
f'--grammar {grammar_path.suffix[1:]} --sppf off '
63+
f'--inputPath {graph_path.parent} --grammarPath {grammar_path} '
64+
f'--outputPath {out_folder} '
65+
'--warmUpRounds 1 --benchmarkRounds 1'
66+
)
67+
68+
@property
69+
def work_dir(self) -> Optional[Path]:
70+
return Path(os.environ['KOTGLL_DIR'])
71+
72+
def parse_results(self, process: subprocess.CompletedProcess[str]) -> CflrToolRunResult:
73+
for line in process.stdout.split('\n'):
74+
if line.startswith('benchmark::'):
75+
parts = line.split()
76+
return CflrToolRunResult(
77+
s_edges=int(parts[-2]),
78+
time_sec=float(parts[-1]),
79+
ram_kb=self.parse_ram_usage_kb(process)
80+
)
81+
raise Exception(f"No results are found in stdout {process.stdout}")
82+
83+
@staticmethod
84+
def _write_kotgll_graph(graph: LabelDecomposedGraph, graph_path: Path) -> None:
85+
with open(graph_path, 'w', encoding="utf-8") as output_file:
86+
for symbol, matrix in graph.matrices.items():
87+
edge_label = symbol.label
88+
(rows, columns, _) = matrix.to_coo()
89+
edges_df = pd.DataFrame({
90+
'source': rows,
91+
'destination': columns,
92+
'label': edge_label
93+
})
94+
csv_string = edges_df.to_csv(sep=' ', index=False, header=False)
95+
output_file.write(csv_string)
96+
97+
@staticmethod
98+
def _explode_grammar(rsm_path: Path, exploded_grammar_path: Path, block_count: int) -> None:
99+
os.makedirs(exploded_grammar_path.parent, exist_ok=True)
100+
with open(rsm_path, 'r') as infile, open(exploded_grammar_path, 'w') as outfile:
101+
for line in infile:
102+
if '{' in line and '}' in line:
103+
for i in range(block_count + 1):
104+
expanded_line = eval(f"f'{line.strip()}'")
105+
outfile.write(expanded_line + '\n')
106+
else:
107+
outfile.write(line)
108+
109+
@staticmethod
110+
def _get_max_memory_gb():
111+
mem_bytes = psutil.virtual_memory().total
112+
mem_gb = mem_bytes / (1024 ** 3)
113+
return int(mem_gb * 0.9)

0 commit comments

Comments
 (0)