|
32 | 32 | "Code-Code/Clone-detection-POJ-104" |
33 | 33 | ), |
34 | 34 | }, |
| 35 | + "poolc": { |
| 36 | + "display_name": "PoolC", |
| 37 | + "source": "PoolC/5-fold-clone-detection-600k-5fold", |
| 38 | + "homepage": "https://huggingface.co/datasets/PoolC/5-fold-clone-detection-600k-5fold", |
| 39 | + }, |
35 | 40 | } |
36 | 41 |
|
37 | 42 | DATASET_ALIASES = { |
|
40 | 45 | "poj": "poj104", |
41 | 46 | "poj-104": "poj104", |
42 | 47 | "codexglue_poj104": "poj104", |
| 48 | + "pool-c": "poolc", |
43 | 49 | } |
44 | 50 |
|
45 | 51 | MANUAL_DATASETS: dict[str, str] = { |
46 | 52 | "gcj": "No stable public direct-download endpoint is registered here.", |
47 | 53 | "karnalim": "No stable public direct-download endpoint is registered here.", |
48 | | - "poolc": "No stable public direct-download endpoint is registered here.", |
49 | 54 | "codenet": "Use the official Project CodeNet release, then prepare subsets locally.", |
50 | 55 | "clcdsa": "Use the official release, then prepare problem directories locally.", |
51 | 56 | "semanticclonebench": "Convert the official released pairs to pair_jsonl locally.", |
@@ -419,6 +424,156 @@ def download_poj104( |
419 | 424 | return report |
420 | 425 |
|
421 | 426 |
|
| 427 | +def download_poolc( |
| 428 | + output_dir: str | Path, |
| 429 | + *, |
| 430 | + overwrite: bool = False, |
| 431 | + hf_cache_dir: str | Path | None = None, |
| 432 | + include_diagnostics: bool = False, |
| 433 | +) -> dict[str, Any]: |
| 434 | + """Download PoolC pair rows and normalize to pair_jsonl layout. |
| 435 | +
|
| 436 | + The Hugging Face release exposes ``train`` and ``val`` splits. This |
| 437 | + repository requires train/validation/test files, so the converter keeps the |
| 438 | + official training split intact and deterministically alternates rows from |
| 439 | + ``val`` into validation and test. |
| 440 | + """ |
| 441 | + destination = Path(output_dir) |
| 442 | + _check_can_write(destination, overwrite) |
| 443 | + load_dataset = _require_hf_datasets() |
| 444 | + try: |
| 445 | + from huggingface_hub import hf_hub_url, list_repo_files |
| 446 | + except ImportError as exc: # pragma: no cover - installed with datasets |
| 447 | + raise RuntimeError( |
| 448 | + "PoolC download requires huggingface_hub, which is installed with " |
| 449 | + "the Hugging Face datasets package." |
| 450 | + ) from exc |
| 451 | + |
| 452 | + spec = AUTO_DATASETS["poolc"] |
| 453 | + repo_files = list_repo_files(spec["source"], repo_type="dataset") |
| 454 | + source_files = { |
| 455 | + "train": sorted( |
| 456 | + file_name |
| 457 | + for file_name in repo_files |
| 458 | + if file_name.startswith("data/train-") and file_name.endswith(".parquet") |
| 459 | + ), |
| 460 | + "val": sorted( |
| 461 | + file_name |
| 462 | + for file_name in repo_files |
| 463 | + if file_name.startswith("data/val-") and file_name.endswith(".parquet") |
| 464 | + ), |
| 465 | + } |
| 466 | + if not source_files["train"] or not source_files["val"]: |
| 467 | + raise ValueError( |
| 468 | + "PoolC source is missing expected data/train-*.parquet or " |
| 469 | + "data/val-*.parquet files." |
| 470 | + ) |
| 471 | + data_files = { |
| 472 | + split_name: [ |
| 473 | + hf_hub_url(spec["source"], filename=file_name, repo_type="dataset") |
| 474 | + for file_name in file_names |
| 475 | + ] |
| 476 | + for split_name, file_names in source_files.items() |
| 477 | + } |
| 478 | + split_rows = {"train": 0, "validation": 0, "test": 0} |
| 479 | + source_split_rows = {"train": 0, "val": 0} |
| 480 | + label_counts = { |
| 481 | + "train": {"0": 0, "1": 0}, |
| 482 | + "validation": {"0": 0, "1": 0}, |
| 483 | + "test": {"0": 0, "1": 0}, |
| 484 | + } |
| 485 | + snippet_hashes: dict[str, str] = {} |
| 486 | + conflict_count = 0 |
| 487 | + |
| 488 | + def write_pair( |
| 489 | + row: Mapping[str, Any], |
| 490 | + split_name: str, |
| 491 | + split_handle: Any, |
| 492 | + data_handle: Any, |
| 493 | + ) -> None: |
| 494 | + nonlocal conflict_count |
| 495 | + left_code = str(row["code1"]) |
| 496 | + right_code = str(row["code2"]) |
| 497 | + label = _label_to_int(row["similar"]) |
| 498 | + left_id = f"poolc:{_text_sha256(left_code)}" |
| 499 | + right_id = f"poolc:{_text_sha256(right_code)}" |
| 500 | + |
| 501 | + for snippet_id, code in ((left_id, left_code), (right_id, right_code)): |
| 502 | + digest = _text_sha256(code) |
| 503 | + previous_digest = snippet_hashes.get(snippet_id) |
| 504 | + if previous_digest is None: |
| 505 | + snippet_hashes[snippet_id] = digest |
| 506 | + data_handle.write(json.dumps({"idx": snippet_id, "func": code}, sort_keys=True)) |
| 507 | + data_handle.write("\n") |
| 508 | + elif previous_digest != digest: |
| 509 | + conflict_count += 1 |
| 510 | + |
| 511 | + split_handle.write(f"{left_id}\t{right_id}\t{label}\n") |
| 512 | + split_rows[split_name] += 1 |
| 513 | + label_counts[split_name][str(label)] += 1 |
| 514 | + |
| 515 | + load_kwargs = {"cache_dir": None if hf_cache_dir is None else str(hf_cache_dir)} |
| 516 | + with (destination / "data.jsonl").open("w", encoding="utf-8") as data_handle: |
| 517 | + train_dataset = load_dataset( |
| 518 | + "parquet", |
| 519 | + data_files={"train": data_files["train"]}, |
| 520 | + split="train", |
| 521 | + streaming=True, |
| 522 | + **load_kwargs, |
| 523 | + ) |
| 524 | + with (destination / "train.txt").open("w", encoding="utf-8") as train_handle: |
| 525 | + for row in train_dataset: |
| 526 | + write_pair(row, "train", train_handle, data_handle) |
| 527 | + source_split_rows["train"] += 1 |
| 528 | + |
| 529 | + val_dataset = load_dataset( |
| 530 | + "parquet", |
| 531 | + data_files={"val": data_files["val"]}, |
| 532 | + split="val", |
| 533 | + streaming=True, |
| 534 | + **load_kwargs, |
| 535 | + ) |
| 536 | + with (destination / "valid.txt").open( |
| 537 | + "w", |
| 538 | + encoding="utf-8", |
| 539 | + ) as validation_handle, (destination / "test.txt").open( |
| 540 | + "w", |
| 541 | + encoding="utf-8", |
| 542 | + ) as test_handle: |
| 543 | + for row_index, row in enumerate(val_dataset): |
| 544 | + split_name = "validation" if row_index % 2 == 0 else "test" |
| 545 | + split_handle = validation_handle if split_name == "validation" else test_handle |
| 546 | + write_pair(row, split_name, split_handle, data_handle) |
| 547 | + source_split_rows["val"] += 1 |
| 548 | + |
| 549 | + if conflict_count: |
| 550 | + raise ValueError( |
| 551 | + f"Encountered {conflict_count} conflicting PoolC snippet ids while " |
| 552 | + "normalizing the dataset." |
| 553 | + ) |
| 554 | + |
| 555 | + report = { |
| 556 | + "dataset_key": "poolc", |
| 557 | + "display_name": spec["display_name"], |
| 558 | + "source": spec["source"], |
| 559 | + "homepage": spec["homepage"], |
| 560 | + "source_files": source_files, |
| 561 | + "layout": "pair_jsonl", |
| 562 | + "source_format": "hf_code_pair_rows", |
| 563 | + "output_dir": str(destination), |
| 564 | + "snippets": len(snippet_hashes), |
| 565 | + "split_rows": split_rows, |
| 566 | + "source_split_rows": source_split_rows, |
| 567 | + "label_counts": label_counts, |
| 568 | + "validation_test_source_split": "val", |
| 569 | + "validation_test_strategy": "alternating_even_odd_rows", |
| 570 | + } |
| 571 | + if include_diagnostics: |
| 572 | + report["diagnostics"] = inspect_dataset_directory(destination) |
| 573 | + _write_json(destination / "dataset_source.json", report) |
| 574 | + return report |
| 575 | + |
| 576 | + |
422 | 577 | def download_dataset( |
423 | 578 | dataset_key: str, |
424 | 579 | output_root: str | Path, |
@@ -453,4 +608,11 @@ def download_dataset( |
453 | 608 | seed=seed, |
454 | 609 | include_diagnostics=include_diagnostics, |
455 | 610 | ) |
| 611 | + if key == "poolc": |
| 612 | + return download_poolc( |
| 613 | + output_dir, |
| 614 | + overwrite=overwrite, |
| 615 | + hf_cache_dir=hf_cache_dir, |
| 616 | + include_diagnostics=include_diagnostics, |
| 617 | + ) |
456 | 618 | raise KeyError(f"Dataset {dataset_key!r} is not registered for automatic download.") |
0 commit comments