File size: 129,861 Bytes
4465cb6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "b058adb1",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 1 β€” Setup"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 38,
      "id": "c6f386e5",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:42:21.472176Z",
          "iopub.status.busy": "2026-06-15T13:42:21.471962Z",
          "iopub.status.idle": "2026-06-15T13:43:43.702809Z",
          "shell.execute_reply": "2026-06-15T13:43:43.701696Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m26.1.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m26.1.2\u001b[0m\n",
            "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n"
          ]
        }
      ],
      "source": [
        "# Install dependencies\n",
        "!pip install datasets rouge-score sentence-transformers transformers torch numpy pandas matplotlib --quiet"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f15399bb",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:43.705792Z",
          "iopub.status.busy": "2026-06-15T13:43:43.705577Z",
          "iopub.status.idle": "2026-06-15T13:43:46.841892Z",
          "shell.execute_reply": "2026-06-15T13:43:46.841163Z"
        }
      },
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "/Users/brandonhalim/Documents/BINUS/NLP/.venv/lib/python3.10/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n",
            "  from .autonotebook import tqdm as notebook_tqdm\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "All imports successful.\n"
          ]
        }
      ],
      "source": [
        "import time\n",
        "import math\n",
        "import re\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "import matplotlib\n",
        "matplotlib.use(\"Agg\", force=True)\n",
        "import matplotlib.pyplot as plt\n",
        "from collections import Counter, defaultdict\n",
        "from datasets import load_dataset\n",
        "from rouge_score import rouge_scorer\n",
        "\n",
        "print(\"All imports successful.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "c407aaf4",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 2 β€” Load Dataset"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 3,
      "id": "b7982f59",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:46.844125Z",
          "iopub.status.busy": "2026-06-15T13:43:46.843870Z",
          "iopub.status.idle": "2026-06-15T13:43:46.846128Z",
          "shell.execute_reply": "2026-06-15T13:43:46.845693Z"
        }
      },
      "outputs": [],
      "source": [
        "# Configuration\n",
        "TOP_N               = 2       # extractive models pick the top-N code statements\n",
        "MIN_FRAGMENT_TOKENS = 3       # statements shorter than this get merged into the previous one\n",
        "SEED                = 42"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "2f233e1d",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:46.847612Z",
          "iopub.status.busy": "2026-06-15T13:43:46.847500Z",
          "iopub.status.idle": "2026-06-15T13:43:52.201506Z",
          "shell.execute_reply": "2026-06-15T13:43:52.200725Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Loading dataset: google/code_x_glue_ct_code_to_text (java) ...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "DatasetDict({\n",
            "    train: Dataset({\n",
            "        features: ['id', 'repo', 'path', 'func_name', 'original_string', 'language', 'code', 'code_tokens', 'docstring', 'docstring_tokens', 'sha', 'url'],\n",
            "        num_rows: 164923\n",
            "    })\n",
            "    validation: Dataset({\n",
            "        features: ['id', 'repo', 'path', 'func_name', 'original_string', 'language', 'code', 'code_tokens', 'docstring', 'docstring_tokens', 'sha', 'url'],\n",
            "        num_rows: 5183\n",
            "    })\n",
            "    test: Dataset({\n",
            "        features: ['id', 'repo', 'path', 'func_name', 'original_string', 'language', 'code', 'code_tokens', 'docstring', 'docstring_tokens', 'sha', 'url'],\n",
            "        num_rows: 10955\n",
            "    })\n",
            "})\n",
            "\n",
            "Fit rows  : 170,106  (train + validation splits)\n",
            "Eval rows : 10,955  (full test split)\n",
            "\n",
            "--- Example row ---\n",
            "code      : private void sign(RequestHandler requestHandler) throws QSException {         if (callBack != null) {             String signed = callBack.onSignature(requestHandler.getStringToSignature());           ...\n",
            "docstring : When sending a request will call this method to sign with server .\n"
          ]
        }
      ],
      "source": [
        "DATASET = \"google/code_x_glue_ct_code_to_text\"\n",
        "FIT_SPLITS = [\"train\", \"validation\"]\n",
        "print(f\"Loading dataset: {DATASET} (java) ...\")\n",
        "\n",
        "dataset = load_dataset(DATASET, \"java\")\n",
        "print(dataset)\n",
        "\n",
        "\n",
        "from datasets import concatenate_datasets\n",
        "fit_data = concatenate_datasets([dataset[split] for split in FIT_SPLITS])\n",
        "\n",
        "eval_data = dataset[\"test\"].shuffle(seed=SEED)\n",
        "\n",
        "def reference_of(row) -> str:\n",
        "    return \" \".join(row[\"docstring_tokens\"]).strip()\n",
        "\n",
        "print(f\"\\nFit rows  : {len(fit_data):,}  ({' + '.join(FIT_SPLITS)} splits)\")\n",
        "print(f\"Eval rows : {len(eval_data):,}  (full test split)\")\n",
        "\n",
        "print(\"\\n--- Example row ---\")\n",
        "ex = eval_data[0]\n",
        "print(\"code      :\", ex[\"code\"][:200].replace(\"\\n\", \" \"), \"...\")\n",
        "print(\"docstring :\", reference_of(ex))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "51693945",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 3 β€” Text Preprocessing"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "439a759b",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:52.203471Z",
          "iopub.status.busy": "2026-06-15T13:43:52.203313Z",
          "iopub.status.idle": "2026-06-15T13:43:52.211630Z",
          "shell.execute_reply": "2026-06-15T13:43:52.211040Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "=== Code-statement splitter demo ===\n",
            "\n",
            "[Row 0] 36 tokens β†’ 5 statements\n",
            "  [0] private void sign(RequestHandler requestHandler) throws QSException\n",
            "  [1] if (callBack != null)\n",
            "  [2] String signed = callBack.onSignature(requestHandler.getStringToSignature()) if (!QSStringUtil.isEmpt...\n",
            "  [3] String correctTime = callBack.onCorrectTime(requestHandler.getStringToSignature())\n",
            "  [4] if (correctTime != null && correctTime.trim().length() > 0) requestHandler.getBuilder().setHeader(QS...\n",
            "\n",
            "[Row 1] 19 tokens β†’ 2 statements\n",
            "  [0] public long offer(final DirectBuffer buffer, final int offset, final int length)\n",
            "  [1] return cluster.offer(id, responsePublication, buffer, offset, length)\n",
            "\n",
            "[Row 2] 90 tokens β†’ 17 statements\n",
            "  [0] public Matrix multiply (final Matrix m) throws MatrixException\n",
            "  [1] // Validate m's dimensions.\n",
            "  [2] if (m_nCols != m.m_nRows)\n",
            "  [3] throw new MatrixException (MatrixException.INVALID_DIMENSIONS)\n",
            "  [4] final float pv[][] = new float [m_nRows] [m.m_nCols]\n",
            "  [5] // product values\n",
            "  [6] // Compute values of the product.\n",
            "  [7] for (int r = 0\n",
            "  [8] r < m_nRows ++r)\n",
            "  [9] for (int c = 0\n",
            "  [10] c < m.m_nCols ++c)\n",
            "  [11] float dot = 0\n",
            "  [12] for (int k = 0\n",
            "  [13] k < m_nCols ++k)\n",
            "  [14] dot += m_aValues[r][k] * m.m_aValues[k][c]\n",
            "  [15] pv[r][c] = dot\n",
            "  [16] return new Matrix (pv)\n"
          ]
        }
      ],
      "source": [
        "STOPWORDS = {\n",
        "\n",
        "    \"public\", \"private\", \"protected\", \"void\", \"new\", \"null\", \"int\", \"string\",\n",
        "    \"static\", \"final\", \"return\", \"class\", \"this\", \"super\", \"true\", \"false\",\n",
        "    \"boolean\", \"long\", \"double\", \"float\", \"byte\", \"char\", \"short\", \"object\",\n",
        "    \"list\", \"map\", \"set\", \"if\", \"else\", \"for\", \"while\", \"do\", \"try\", \"catch\",\n",
        "    \"finally\", \"throw\", \"throws\", \"import\", \"package\", \"extends\", \"implements\",\n",
        "    \"instanceof\", \"interface\", \"abstract\", \"synchronized\", \"volatile\",\n",
        "    \"a\", \"an\", \"the\", \"and\", \"or\", \"but\", \"in\", \"on\", \"at\", \"to\", \"of\",\n",
        "    \"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\", \"have\", \"has\", \"had\",\n",
        "    \"do\", \"does\", \"did\", \"will\", \"would\", \"could\", \"should\", \"may\", \"might\",\n",
        "    \"it\", \"its\", \"with\", \"for\", \"not\", \"by\", \"from\", \"as\", \"that\", \"this\",\n",
        "    \"which\", \"who\", \"when\", \"where\", \"how\", \"all\", \"each\", \"both\", \"more\",\n",
        "    \"s\", \"e\", \n",
        "}\n",
        "\n",
        "_SUBWORD_RE = re.compile(r\"[A-Z]+(?=[A-Z][a-z])|[A-Z]?[a-z]+|[A-Z]+|\\d+\")\n",
        "\n",
        "\n",
        "def split_identifier(token: str) -> list[str]:\n",
        "    out = []\n",
        "    for part in re.split(r\"[_\\s]+\", token):\n",
        "        out.extend(_SUBWORD_RE.findall(part))\n",
        "    return [w.lower() for w in out if w]\n",
        "\n",
        "\n",
        "def tokenize(text: str) -> list[str]:\n",
        "    toks = []\n",
        "    for raw in text.split():\n",
        "        for sub in split_identifier(raw):\n",
        "            if sub and sub not in STOPWORDS:\n",
        "                toks.append(sub)\n",
        "    return toks\n",
        "\n",
        "\n",
        "def split_code_statements(code: str) -> list[str]:\n",
        "    parts = re.split(r\"[;{}\\n]\", code)\n",
        "    frags = [re.sub(r\"\\s+\", \" \", p).strip() for p in parts]\n",
        "    frags = [f for f in frags if f]\n",
        "\n",
        "    merged = []\n",
        "    for frag in frags:\n",
        "        if len(frag.split()) < MIN_FRAGMENT_TOKENS and merged:\n",
        "            merged[-1] += \" \" + frag\n",
        "        else:\n",
        "            merged.append(frag)\n",
        "\n",
        "    return merged if merged else [re.sub(r\"\\s+\", \" \", code).strip()]\n",
        "\n",
        "\n",
        "print(\"=== Code-statement splitter demo ===\")\n",
        "for i in range(3):\n",
        "    row = eval_data[i]\n",
        "    code = row[\"code\"]\n",
        "    sents = split_code_statements(code)\n",
        "    print(f\"\\n[Row {i}] {len(code.split())} tokens β†’ {len(sents)} statements\")\n",
        "    for j, s in enumerate(sents):\n",
        "        print(f\"  [{j}] {s[:100]}{'...' if len(s) > 100 else ''}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "49c53b4f",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 4 β€” Build Fitting Corpus"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 14,
      "id": "69a01192",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:52.213144Z",
          "iopub.status.busy": "2026-06-15T13:43:52.213023Z",
          "iopub.status.idle": "2026-06-15T13:43:52.757398Z",
          "shell.execute_reply": "2026-06-15T13:43:52.756885Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Building fit corpus from train + validation splits ...\n",
            "Fit corpus size: 1,278,409 statements from 170,106 methods\n"
          ]
        }
      ],
      "source": [
        "print(f\"Building fit corpus from {' + '.join(FIT_SPLITS)} splits ...\")\n",
        "fit_corpus = []\n",
        "for row in fit_data:\n",
        "    fit_corpus.extend(split_code_statements(row[\"code\"]))\n",
        "\n",
        "print(f\"Fit corpus size: {len(fit_corpus):,} statements from {len(fit_data):,} methods\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "34e36450",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 5 β€” Models\n",
        "### 5.1 TF-IDF"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 16,
      "id": "331089b7",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:52.759648Z",
          "iopub.status.busy": "2026-06-15T13:43:52.759477Z",
          "iopub.status.idle": "2026-06-15T13:43:52.763523Z",
          "shell.execute_reply": "2026-06-15T13:43:52.763038Z"
        }
      },
      "outputs": [],
      "source": [
        "class TFIDFModel:\n",
        "\n",
        "    def fit(self, corpus: list[str]):\n",
        "        N = len(corpus)\n",
        "        df = defaultdict(int)\n",
        "        for sent in corpus:\n",
        "            for term in set(tokenize(sent)):\n",
        "                df[term] += 1\n",
        "        self.idf = {term: math.log((N + 1) / (freq + 1)) + 1 \n",
        "            for term, freq in df.items()}\n",
        "\n",
        "        self.N = N\n",
        "        return self\n",
        "\n",
        "    def _score(self, sentence: str) -> float:\n",
        "        tokens = tokenize(sentence)\n",
        "        if not tokens:\n",
        "            return 0.0\n",
        "        tf = Counter(tokens)\n",
        "        return sum(tf[t] / len(tokens) * self.idf.get(t, 1.0) \n",
        "               for t in tf)\n",
        "\n",
        "    def summarize(self, sentences: list[str], top_n: int = 1) -> list[str]:\n",
        "        if not sentences:\n",
        "            return [\"\"]\n",
        "        scored = sorted(sentences, key=self._score, reverse=True)\n",
        "        return scored[:top_n]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "5f13e6b5",
      "metadata": {},
      "source": [
        "### 5.2 LexRank"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 17,
      "id": "52171f64",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:52.764997Z",
          "iopub.status.busy": "2026-06-15T13:43:52.764902Z",
          "iopub.status.idle": "2026-06-15T13:43:52.772839Z",
          "shell.execute_reply": "2026-06-15T13:43:52.772337Z"
        }
      },
      "outputs": [],
      "source": [
        "class LexRankModel:\n",
        "    THRESHOLD = 0.1\n",
        "    DAMPING   = 0.85\n",
        "    MAX_ITER  = 100\n",
        "    TOL       = 1e-6\n",
        "\n",
        "    def fit(self, corpus: list[str]):\n",
        "        N = len(corpus)\n",
        "        df = defaultdict(int)\n",
        "        for sent in corpus:\n",
        "            for term in set(tokenize(sent)):\n",
        "                df[term] += 1\n",
        "        self.idf = {term: math.log((N + 1) / (freq + 1)) + 1\n",
        "                    for term, freq in df.items()}\n",
        "        return self\n",
        "\n",
        "    def _tfidf_vec(self, sentence: str) -> dict[str, float]:\n",
        "        tokens = tokenize(sentence)\n",
        "        if not tokens:\n",
        "            return {}\n",
        "        tf = Counter(tokens)\n",
        "        return {t: (tf[t] / len(tokens)) * self.idf.get(t, 1.0) for t in tf}\n",
        "\n",
        "    @staticmethod\n",
        "    def _cosine(a: dict, b: dict) -> float:\n",
        "        common = set(a) & set(b)\n",
        "        if not common:\n",
        "            return 0.0\n",
        "        dot   = sum(a[t] * b[t] for t in common)\n",
        "        norm_a = math.sqrt(sum(v ** 2 for v in a.values()))\n",
        "        norm_b = math.sqrt(sum(v ** 2 for v in b.values()))\n",
        "        if norm_a == 0 or norm_b == 0:\n",
        "            return 0.0\n",
        "        return dot / (norm_a * norm_b)\n",
        "\n",
        "    def _pagerank(self, matrix: np.ndarray) -> np.ndarray:\n",
        "        n = len(matrix)\n",
        "        # Row-normalise\n",
        "        row_sums = matrix.sum(axis=1, keepdims=True)\n",
        "        row_sums[row_sums == 0] = 1\n",
        "        P = matrix / row_sums\n",
        "        scores = np.ones(n) / n\n",
        "        for _ in range(self.MAX_ITER):\n",
        "            new_scores = (1 - self.DAMPING) / n + self.DAMPING * P.T @ scores\n",
        "            if np.abs(new_scores - scores).sum() < self.TOL:\n",
        "                break\n",
        "            scores = new_scores\n",
        "        return scores\n",
        "\n",
        "    def summarize(self, sentences: list[str], top_n: int = 1) -> list[str]:\n",
        "        if len(sentences) == 1:\n",
        "            return sentences[:top_n]\n",
        "        vecs = [self._tfidf_vec(s) for s in sentences]\n",
        "        n = len(sentences)\n",
        "        sim = np.zeros((n, n))\n",
        "        for i in range(n):\n",
        "            for j in range(i + 1, n):\n",
        "                c = self._cosine(vecs[i], vecs[j])\n",
        "                if c >= self.THRESHOLD:\n",
        "                    sim[i, j] = sim[j, i] = c\n",
        "        # Fall back to TF-IDF scoring if graph is empty\n",
        "        if sim.sum() == 0:\n",
        "            scored = sorted(range(n),\n",
        "                            key=lambda i: sum(vecs[i].values()), reverse=True)\n",
        "            return [sentences[i] for i in scored[:top_n]]\n",
        "        scores = self._pagerank(sim)\n",
        "        ranked = np.argsort(scores)[::-1]\n",
        "        return [sentences[i] for i in ranked[:top_n]]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "7ced0ea0",
      "metadata": {},
      "source": [
        "### 5.3 SentenceTransformers"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "df052e02",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:52.774353Z",
          "iopub.status.busy": "2026-06-15T13:43:52.774237Z",
          "iopub.status.idle": "2026-06-15T13:43:56.077349Z",
          "shell.execute_reply": "2026-06-15T13:43:56.076774Z"
        }
      },
      "outputs": [],
      "source": [
        "from sentence_transformers import SentenceTransformer\n",
        "\n",
        "class SentenceTransformerModel:\n",
        "    def __init__(self, model_name: str = \"all-MiniLM-L6-v2\"):\n",
        "        print(f\"Loading SentenceTransformer: {model_name} ...\")\n",
        "        self.model = SentenceTransformer(model_name)\n",
        "\n",
        "    def summarize(self, sentences: list[str], top_n: int = 1) -> list[str]:\n",
        "        if not sentences:\n",
        "            return [\"\"]\n",
        "        embeddings = self.model.encode(sentences, convert_to_numpy=True)\n",
        "        centroid   = embeddings.mean(axis=0)\n",
        "\n",
        "        norms = np.linalg.norm(embeddings, axis=1, keepdims=True)\n",
        "        norms[norms == 0] = 1\n",
        "        sims  = (embeddings / norms) @ (centroid / (np.linalg.norm(centroid) + 1e-9))\n",
        "        ranked = np.argsort(sims)[::-1]\n",
        "        return [sentences[i] for i in ranked[:top_n]]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "932e21f7",
      "metadata": {},
      "source": [
        "### 5.4 CodeT5"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "37bf9773",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:56.079233Z",
          "iopub.status.busy": "2026-06-15T13:43:56.078983Z",
          "iopub.status.idle": "2026-06-15T13:43:56.084468Z",
          "shell.execute_reply": "2026-06-15T13:43:56.083822Z"
        }
      },
      "outputs": [],
      "source": [
        "from transformers import AutoModelForSeq2SeqLM\n",
        "from huggingface_hub import hf_hub_download\n",
        "from tokenizers import ByteLevelBPETokenizer\n",
        "import torch\n",
        "\n",
        "class CodeT5Model:\n",
        "\n",
        "    MODEL_NAME = \"Salesforce/codet5-base-codexglue-sum-java\"\n",
        "    VOCAB_REPO = \"Salesforce/codet5-base\"\n",
        "    _SPECIAL_TOKENS = (\"<pad>\", \"<s>\", \"</s>\", \"<unk>\", \"<mask>\")\n",
        "\n",
        "    def __init__(self):\n",
        "        print(f\"Loading CodeT5: {self.MODEL_NAME} ...\")\n",
        "        vocab_file  = hf_hub_download(self.VOCAB_REPO, \"vocab.json\")\n",
        "        merges_file = hf_hub_download(self.VOCAB_REPO, \"merges.txt\")\n",
        "        self.tokenizer = ByteLevelBPETokenizer(vocab_file, merges_file)\n",
        "\n",
        "        self.model  = AutoModelForSeq2SeqLM.from_pretrained(self.MODEL_NAME)\n",
        "        self.device = \"cuda\" if torch.cuda.is_available() else \"cpu\"\n",
        "        self.model.to(self.device)\n",
        "        self.model.eval()\n",
        "        print(f\"  Running on: {self.device}\")\n",
        "\n",
        "    def _clean(self, text: str) -> str:\n",
        "        for tok in self._SPECIAL_TOKENS:\n",
        "            text = text.replace(tok, \" \")\n",
        "        text = re.sub(r\"<extra_id_\\d+>\", \" \", text)\n",
        "        return re.sub(r\"\\s+\", \" \", text).strip()\n",
        "\n",
        "    def summarize(self, raw_code: str) -> str:\n",
        "        if not raw_code or not raw_code.strip():\n",
        "            return \"\"\n",
        "\n",
        "        ids = self.tokenizer.encode(raw_code).ids[:256]\n",
        "        input_ids = torch.tensor([ids], device=self.device)\n",
        "        attention = torch.ones_like(input_ids)\n",
        "\n",
        "        with torch.no_grad():\n",
        "            output_ids = self.model.generate(\n",
        "                input_ids=input_ids,\n",
        "                attention_mask=attention,\n",
        "                max_new_tokens=48,\n",
        "                num_beams=4,\n",
        "                early_stopping=True,\n",
        "                no_repeat_ngram_size=3,\n",
        "            )\n",
        "\n",
        "        decoded = self.tokenizer.decode(output_ids[0].tolist(), skip_special_tokens=False)\n",
        "        return self._clean(decoded)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "2294a00d",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 6 β€” Fit Traditional Models"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 20,
      "id": "af6d950c",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:43:56.086043Z",
          "iopub.status.busy": "2026-06-15T13:43:56.085910Z",
          "iopub.status.idle": "2026-06-15T13:44:05.515071Z",
          "shell.execute_reply": "2026-06-15T13:44:05.513912Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Fitting TF-IDF ...\n",
            "  Done in 12.70s\n",
            "Fitting LexRank ...\n",
            "  Done in 12.47s\n",
            "Loading SentenceTransformers ...\n",
            "Loading SentenceTransformer: all-MiniLM-L6-v2 ...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Loading weights: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 103/103 [00:00<00:00, 7722.80it/s]\n",
            "\u001b[1mBertModel LOAD REPORT\u001b[0m from: sentence-transformers/all-MiniLM-L6-v2\n",
            "Key                     | Status     |  | \n",
            "------------------------+------------+--+-\n",
            "embeddings.position_ids | UNEXPECTED |  | \n",
            "\n",
            "\u001b[3mNotes:\n",
            "- UNEXPECTED\u001b[3m\t:can be ignored when loading from different task/architecture; not ok if you expect identical arch.\u001b[0m\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "  Done in 6.79s\n",
            "Loading CodeT5 ...\n",
            "Loading CodeT5: Salesforce/codet5-base-codexglue-sum-java ...\n"
          ]
        },
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "Loading weights: 100%|β–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆβ–ˆ| 260/260 [00:00<00:00, 34062.75it/s]\n",
            "The tied weights mapping and config for this model specifies to tie shared.weight to lm_head.weight, but both are present in the checkpoints, so we will NOT tie them. You should update the config with `tie_word_embeddings=False` to silence this warning\n",
            "The tied weights mapping and config for this model specifies to tie shared.weight to encoder.embed_tokens.weight, but both are present in the checkpoints, so we will NOT tie them. You should update the config with `tie_word_embeddings=False` to silence this warning\n",
            "The tied weights mapping and config for this model specifies to tie shared.weight to decoder.embed_tokens.weight, but both are present in the checkpoints, so we will NOT tie them. You should update the config with `tie_word_embeddings=False` to silence this warning\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "  Running on: cpu\n",
            "  Done in 2.24s\n"
          ]
        }
      ],
      "source": [
        "print(\"Fitting TF-IDF ...\")\n",
        "t0 = time.perf_counter()\n",
        "tfidf_model = TFIDFModel().fit(fit_corpus)\n",
        "print(f\"  Done in {time.perf_counter() - t0:.2f}s\")\n",
        "\n",
        "print(\"Fitting LexRank ...\")\n",
        "t0 = time.perf_counter()\n",
        "lexrank_model = LexRankModel().fit(fit_corpus)\n",
        "print(f\"  Done in {time.perf_counter() - t0:.2f}s\")\n",
        "\n",
        "print(\"Loading SentenceTransformers ...\")\n",
        "t0 = time.perf_counter()\n",
        "st_model = SentenceTransformerModel()\n",
        "print(f\"  Done in {time.perf_counter() - t0:.2f}s\")\n",
        "\n",
        "print(\"Loading CodeT5 ...\")\n",
        "t0 = time.perf_counter()\n",
        "codet5_model = CodeT5Model()\n",
        "print(f\"  Done in {time.perf_counter() - t0:.2f}s\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "13e40a5d",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 7 β€” Evaluation Loop"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "24950a88",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:44:05.517510Z",
          "iopub.status.busy": "2026-06-15T13:44:05.517320Z",
          "iopub.status.idle": "2026-06-15T13:47:05.676884Z",
          "shell.execute_reply": "2026-06-15T13:47:05.675837Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Evaluating on 10,955 test rows ...\n",
            "  [500/10955] elapsed: 360.6s\n",
            "  [1000/10955] elapsed: 716.5s\n",
            "  [1500/10955] elapsed: 1065.1s\n",
            "  [2000/10955] elapsed: 1440.4s\n",
            "  [2500/10955] elapsed: 1815.1s\n",
            "  [3000/10955] elapsed: 2185.8s\n",
            "  [3500/10955] elapsed: 2576.7s\n",
            "  [4000/10955] elapsed: 2962.7s\n",
            "  [4500/10955] elapsed: 3314.1s\n",
            "  [5000/10955] elapsed: 3664.1s\n",
            "  [5500/10955] elapsed: 4012.1s\n",
            "  [6000/10955] elapsed: 4362.6s\n",
            "  [6500/10955] elapsed: 4714.1s\n",
            "  [7000/10955] elapsed: 5062.2s\n",
            "  [7500/10955] elapsed: 5408.1s\n",
            "  [8000/10955] elapsed: 5758.0s\n",
            "  [8500/10955] elapsed: 6111.9s\n",
            "  [9000/10955] elapsed: 6470.6s\n",
            "  [9500/10955] elapsed: 6827.7s\n",
            "  [10000/10955] elapsed: 7186.2s\n",
            "  [10500/10955] elapsed: 7540.9s\n",
            "  [10955/10955] elapsed: 7851.8s\n",
            "\n",
            "Evaluation complete in 7851.9s\n"
          ]
        }
      ],
      "source": [
        "scorer = rouge_scorer.RougeScorer([\"rouge1\", \"rouge2\", \"rougeL\"], use_stemmer=True)\n",
        "\n",
        "def rouge_scores(prediction: str, reference: str) -> dict:\n",
        "    scores = scorer.score(reference, prediction)\n",
        "    return {\n",
        "        \"rouge1\": scores[\"rouge1\"].fmeasure,\n",
        "        \"rouge2\": scores[\"rouge2\"].fmeasure,\n",
        "        \"rougeL\": scores[\"rougeL\"].fmeasure,\n",
        "    }\n",
        "\n",
        "results = []\n",
        "\n",
        "eval_n = len(eval_data)\n",
        "print(f\"Evaluating on {eval_n:,} test rows ...\")\n",
        "t_start = time.perf_counter()\n",
        "\n",
        "for idx, row in enumerate(eval_data):\n",
        "    code      = row[\"code\"]\n",
        "    reference = reference_of(row)\n",
        "    statements = split_code_statements(code)\n",
        "\n",
        "    tfidf_out    = \" \".join(tfidf_model.summarize(statements, TOP_N))\n",
        "    tfidf_scores = rouge_scores(tfidf_out, reference)\n",
        "\n",
        "    lexrank_out    = \" \".join(lexrank_model.summarize(statements, TOP_N))\n",
        "    lexrank_scores = rouge_scores(lexrank_out, reference)\n",
        "\n",
        "    st_out    = \" \".join(st_model.summarize(statements, TOP_N))\n",
        "    st_scores = rouge_scores(st_out, reference)\n",
        "\n",
        "    ct5_out    = codet5_model.summarize(code)\n",
        "    ct5_scores = rouge_scores(ct5_out, reference)\n",
        "\n",
        "    results.append({\n",
        "        \"row_id\"    : idx,\n",
        "        \"reference\" : reference,\n",
        "        \"tfidf_out\"    : tfidf_out,\n",
        "        \"lexrank_out\"  : lexrank_out,\n",
        "        \"st_out\"       : st_out,\n",
        "        \"codet5_out\"   : ct5_out,\n",
        "        # ROUGE scores\n",
        "        \"tfidf_r1\"    : tfidf_scores[\"rouge1\"],\n",
        "        \"tfidf_r2\"    : tfidf_scores[\"rouge2\"],\n",
        "        \"tfidf_rL\"    : tfidf_scores[\"rougeL\"],\n",
        "        \"lexrank_r1\"  : lexrank_scores[\"rouge1\"],\n",
        "        \"lexrank_r2\"  : lexrank_scores[\"rouge2\"],\n",
        "        \"lexrank_rL\"  : lexrank_scores[\"rougeL\"],\n",
        "        \"st_r1\"       : st_scores[\"rouge1\"],\n",
        "        \"st_r2\"       : st_scores[\"rouge2\"],\n",
        "        \"st_rL\"       : st_scores[\"rougeL\"],\n",
        "        \"codet5_r1\"   : ct5_scores[\"rouge1\"],\n",
        "        \"codet5_r2\"   : ct5_scores[\"rouge2\"],\n",
        "        \"codet5_rL\"   : ct5_scores[\"rougeL\"],\n",
        "    })\n",
        "\n",
        "    if (idx + 1) % 500 == 0 or (idx + 1) == eval_n:\n",
        "        elapsed = time.perf_counter() - t_start\n",
        "        print(f\"  [{idx + 1}/{eval_n}] elapsed: {elapsed:.1f}s\")\n",
        "\n",
        "results_df = pd.DataFrame(results)\n",
        "print(f\"\\nEvaluation complete in {time.perf_counter() - t_start:.1f}s\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "147b1280",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 8 β€” Results Table"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 29,
      "id": "3785beae",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:47:05.682386Z",
          "iopub.status.busy": "2026-06-15T13:47:05.682199Z",
          "iopub.status.idle": "2026-06-15T13:47:05.706801Z",
          "shell.execute_reply": "2026-06-15T13:47:05.706169Z"
        }
      },
      "outputs": [
        {
          "data": {
            "text/html": [
              "<div>\n",
              "<style scoped>\n",
              "    .dataframe tbody tr th:only-of-type {\n",
              "        vertical-align: middle;\n",
              "    }\n",
              "\n",
              "    .dataframe tbody tr th {\n",
              "        vertical-align: top;\n",
              "    }\n",
              "\n",
              "    .dataframe thead th {\n",
              "        text-align: right;\n",
              "    }\n",
              "</style>\n",
              "<table border=\"1\" class=\"dataframe\">\n",
              "  <thead>\n",
              "    <tr style=\"text-align: right;\">\n",
              "      <th></th>\n",
              "      <th>Model</th>\n",
              "      <th>Tier</th>\n",
              "      <th>Type</th>\n",
              "      <th>ROUGE-1</th>\n",
              "      <th>ROUGE-2</th>\n",
              "      <th>ROUGE-L</th>\n",
              "    </tr>\n",
              "  </thead>\n",
              "  <tbody>\n",
              "    <tr>\n",
              "      <th>0</th>\n",
              "      <td>CodeT5 βš‘</td>\n",
              "      <td>Code-specific fine-tuned</td>\n",
              "      <td>Abstractive</td>\n",
              "      <td>0.3722</td>\n",
              "      <td>0.1511</td>\n",
              "      <td>0.3433</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>1</th>\n",
              "      <td>TF-IDF</td>\n",
              "      <td>Corpus-fitted extractive</td>\n",
              "      <td>Extractive</td>\n",
              "      <td>0.1110</td>\n",
              "      <td>0.0093</td>\n",
              "      <td>0.0963</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>2</th>\n",
              "      <td>LexRank</td>\n",
              "      <td>Corpus-fitted extractive</td>\n",
              "      <td>Extractive</td>\n",
              "      <td>0.1039</td>\n",
              "      <td>0.0071</td>\n",
              "      <td>0.0921</td>\n",
              "    </tr>\n",
              "    <tr>\n",
              "      <th>3</th>\n",
              "      <td>SentenceTransformers</td>\n",
              "      <td>General-language pretrained</td>\n",
              "      <td>Extractive</td>\n",
              "      <td>0.1023</td>\n",
              "      <td>0.0074</td>\n",
              "      <td>0.0905</td>\n",
              "    </tr>\n",
              "  </tbody>\n",
              "</table>\n",
              "</div>"
            ],
            "text/plain": [
              "                  Model                         Tier         Type  ROUGE-1  \\\n",
              "0              CodeT5 βš‘     Code-specific fine-tuned  Abstractive   0.3722   \n",
              "1                TF-IDF     Corpus-fitted extractive   Extractive   0.1110   \n",
              "2               LexRank     Corpus-fitted extractive   Extractive   0.1039   \n",
              "3  SentenceTransformers  General-language pretrained   Extractive   0.1023   \n",
              "\n",
              "   ROUGE-2  ROUGE-L  \n",
              "0   0.1511   0.3433  \n",
              "1   0.0093   0.0963  \n",
              "2   0.0071   0.0921  \n",
              "3   0.0074   0.0905  "
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        }
      ],
      "source": [
        "agg = pd.DataFrame([\n",
        "    {\n",
        "        \"Model\"   : \"TF-IDF\",\n",
        "        \"Tier\"    : \"Corpus-fitted extractive\",\n",
        "        \"Type\"    : \"Extractive\",\n",
        "        \"ROUGE-1\" : results_df[\"tfidf_r1\"].mean(),\n",
        "        \"ROUGE-2\" : results_df[\"tfidf_r2\"].mean(),\n",
        "        \"ROUGE-L\" : results_df[\"tfidf_rL\"].mean(),\n",
        "    },\n",
        "    {\n",
        "        \"Model\"   : \"LexRank\",\n",
        "        \"Tier\"    : \"Corpus-fitted extractive\",\n",
        "        \"Type\"    : \"Extractive\",\n",
        "        \"ROUGE-1\" : results_df[\"lexrank_r1\"].mean(),\n",
        "        \"ROUGE-2\" : results_df[\"lexrank_r2\"].mean(),\n",
        "        \"ROUGE-L\" : results_df[\"lexrank_rL\"].mean(),\n",
        "    },\n",
        "    {\n",
        "        \"Model\"   : \"SentenceTransformers\",\n",
        "        \"Tier\"    : \"General-language pretrained\",\n",
        "        \"Type\"    : \"Extractive\",\n",
        "        \"ROUGE-1\" : results_df[\"st_r1\"].mean(),\n",
        "        \"ROUGE-2\" : results_df[\"st_r2\"].mean(),\n",
        "        \"ROUGE-L\" : results_df[\"st_rL\"].mean(),\n",
        "    },\n",
        "    {\n",
        "        \"Model\"   : \"CodeT5 βš‘\",\n",
        "        \"Tier\"    : \"Code-specific fine-tuned\",\n",
        "        \"Type\"    : \"Abstractive\",\n",
        "        \"ROUGE-1\" : results_df[\"codet5_r1\"].mean(),\n",
        "        \"ROUGE-2\" : results_df[\"codet5_r2\"].mean(),\n",
        "        \"ROUGE-L\" : results_df[\"codet5_rL\"].mean(),\n",
        "    },\n",
        "])\n",
        "\n",
        "agg = agg.sort_values(\"ROUGE-L\", ascending=False).reset_index(drop=True)\n",
        "\n",
        "\n",
        "pd.set_option(\"display.float_format\", \"{:.4f}\".format)\n",
        "display(agg)"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "108fb5ea",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 9 β€” Comparison Chart"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 25,
      "id": "48b9df44",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:47:05.713077Z",
          "iopub.status.busy": "2026-06-15T13:47:05.712931Z",
          "iopub.status.idle": "2026-06-15T13:47:05.994850Z",
          "shell.execute_reply": "2026-06-15T13:47:05.994153Z"
        }
      },
      "outputs": [
        {
          "data": {
            "image/png": "iVBORw0KGgoAAAANSUhEUgAABdwAAALuCAYAAAC0INRMAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/NK7nSAAAACXBIWXMAABcSAAAXEgFnn9JSAAD5RklEQVR4nOzdd1hUx/s28HvpvQgIAlIUREXFFcECKmpssSaxl4CJLZYYjS2aKCYxGnui0ZhoxFgSYv3F2CuKvSCKRmxgRQVsSBfm/YN3z5d1d2HBRTDen+viuvTMmTnPqQvPmZ2RCSEEiIiIiIiIiIiIiIjoleiVdwBERERERERERERERP8FTLgTEREREREREREREekAE+5ERERERERERERERDrAhDsRERERERERERERkQ4w4U5EREREREREREREpANMuBMRERERERERERER6QAT7kREREREREREREREOsCEOxERERERERERERGRDjDhTkRERERERERERESkA0y4ExERERERERERERHpABPuREREREREREREREQ6wIQ7EREREREREREREZEOMOFORERERERERERERKQDTLgTEREREREREREREekAE+5ERERERERERERERDrAhDsRERERERERERERkQ4w4U5EREREREREREREpANMuBMRERERERERERER6QAT7kREREREREREREREOsCEOxERERERERERERGRDjDhTkRERERERERERESkA0y4ExERERERERERERHpABPuREREREREREREREQ6wIQ7ERERlcjBgwchk8kQEhJS3qFolJiYCJlMBg8Pj/IO5T9DJpNBJpPprL2wsDDIZDJERETorE3Snbf1/Cj2++DBg+Udymv3tp5zIiIiIl1jwp2IiN449+/fx5QpU9CgQQNYWVnByMgIVapUQf369TFo0CCsXr0az58/L+8wqQyFh4cjPDwcT548Ke9QXpmHh4eUzO7Tp0+R6167dk1al4kxYPv27QgLC4O3tzesrKxgbGwMZ2dndOjQAYsXL8bjx4/LO0QiKienTp3CggUL0LdvX3h7e5f4uXnjxg189NFHcHV1hbGxMapWrYqPP/4YCQkJpY4pPT0ds2bNQoMGDWBpaQkLCwvUr18fs2fPRk5OjsZ6hT8nNP1kZWWp1FO8IC/qp3fv3qXen8IUL2xK+hMeHq7S1tOnT/H9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4tGjR8jLy4O+vn55h0RERBVUdHQ0PDw8SjXUDhHRf112djbCw8OLHJKQiIheDRPuRET0RlCM5U5ERFSUTZs2lXcIREQVVt++fcs7BCKi/zwOKUNEREREREREREREpAOcNJWIiIiIiIiIiIiISAfYw52IiIiIiIiIiIiISAeYcCciIiIiIiIiIiIi0gEm3ImIiIiIiIiIiIiIdIAJdyIiIiIiIiIiIiIiHWDCnYiIiIiIiIiIiIhIB5hwJyIiIiIiIiIiIiLSAYPyDoCK5uTkhPT0dLi5uZV3KERERERERERERERvvFu3bsHc3Bz379/Xedvs4V7BpaenIzc3t7zDICIiIiIiIiIiIvpPyM3NRXp6epm0zR7uFZyiZ/vFixfLORIiIiIiIiIiIiKiN5+vr2+Ztc0e7kREREREREREREREOsCEOxERERERERERERGRDjDhTkRERERERERERESkA0y4ExERERERERERERHpABPuREREREREREREREQ6wIQ7EREREREREREREZEOGJR3AERERERERERERPRmEEJACFHeYRABAGQyGWQyWXmHoYQJdyIiIiIiIiIiItIoLy8PqampSEtLQ05OTnmHQ6TEyMgIlpaWsLOzg76+fnmHw4Q7ERERERERERERqZeXl4dbt24hKyurvEMhUisnJwepqalIT0+Hm5tbuSfdmXAnIiIiIiIiIiIitVJTU5GVlQV9fX04OjrC3NwcenqcFpIqhvz8fKSnp+PBgwfIyspCamoqKleuXK4xMeFOREREREREREREaqWlpQEAHB0dYW1tXc7RECnT09OTrst79+4hLS2t3BPufB1FREREREREREREKoQQ0pjt5ubm5RwNkWaK6zMnJ6fcJ/Vlwp2IiIiIiIiIiIhUFE5cchgZqsgKX59MuBMRERERERERERER/Qcw4U5EREREREREREREpANMuBMRERERERERERER6QAT7kREREREREREREREOsCEOxEREREREREREVEJyGQypR89PT1YW1ujcePGWLhwIXJzc4usL4RAZGQkOnfuDGdnZxgbG6Ny5cpo3bo1li1bprF+REQEZDIZQkJCimzfw8MDMpkMBw8eVFuem5uLlStXokuXLnB1dYWJiQnMzc3h5eWF3r17Y926dcjOzlapFxISorLvL/94eHgUGdvLoqKiMH36dHTs2BEO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ODo64t1330XXrl3xwQcfwNTUVG0bxY1Bv3DhQq0T7nfu3FEZHicnJ0dp2bNnz7RqqyJgD/cKjj3ciYiIiIiIiIioPJS01zBRealIPdx5lxARERERERERERER6QAT7kREREREREREREREOsCEOxERERERERERERGRDjDhTkRERERERERERESkA0y4ExERERERERERERHpABPuREREREREREREREQ6wIQ7EREREREREREREZEOMOFORERERERERERERKQDTLgTEREREREREREREekAE+5ERERERERERERERDrAhDsRERERERERERERkQ4w4U5EREREREREREREpANMuBMRERERERERERER6QAT7kREREREREREREQlIJPJlH709PRgbW2Nxo0bY+HChcjNzS2yvhACkZGR6Ny5M5ydnWFsbIzKlSujdevWWLZsmcb6ERERkMlkCAkJKbJ9Dw8PyGQyHDx4UG15bm4uVq5ciS5dusDV1RUmJiYwNzeHl5cXevfujXXr1iE7O1ulXkhIiMq+v/zj4eFRZGyFPXnyBOvWrUOfPn3g6ekJIyMjWFpaolGjRvjhhx+KPY4VkUF5B0BERERERERERERvrhszPijvELRSbcpGnbcZGhoKAMjLy0NiYiKOHj2KEydO4J9//sHOnTthYKCafn38+DHee+89REVFQV9fH02aNEFISAiSk5MRHR2N/fv3Y/Hixdi2bRvc3Nx0HvPly5fRrVs3xMfHw8DAAP7+/ggKCkJeXh5u3ryJ9evXIzIyEhMnTsT58+dha2ur0ka7du3g5OSktn17e3utY5k7dy5mzJgBmUyG+vXro1GjRkhOTsaRI0dw8uRJbNiwAbt27YKZmVmp9/d1Y8KdiIiIiIiIiIiIqBQiIiKU/n/ixAmEhIRg3759+PPPP9G/f3+l8tzcXLRv3x4nT55Es2bNsHr1ari7u0vlqampGDp0KDZu3IiQkBDExMTA2tpaZ/HeunULwcHBSE1NRWhoKL7//ns4OjoqrZOSkoIlS5Zg9uzZSE9PV5twnzRpUrG97LVhbm6OCRMmYMSIEUovF65evYp33nkH0dHR+Pbbb/Hdd9+98rZeFw4pQ0RERERERERERKQDjRo1QlhYGABg165dKuXz5s3DyZMnUbt2bezcuVMp2Q4AdnZ2iIyMRKtWrZCQkIBJkybpNL4hQ4YgNTUVgwYNQkREhEqyHSjooT516lSdJ/vV+eKLL/D999+r9OT39vbGrFmzAAB//PFHmcaga0y4ExEREREREREREemIr68vAODhw4dKy1+8eIEff/wRADB79myNw6To6+vjhx9+AFDQg/7Ro0c6iSsuLk4anmXu3LnFru/t7Q1LS0udbLs0/Pz8AAD37t0rtxhKgwl3IiIiIiIiIiIiIh1JS0sDAFSuXFlpeUxMDJKSklCpUiW0b9++yDbq1KmDevXqISsrCwcOHNBJXDt27AAAdOjQocx7ruvCjRs3AEDjWPEVFRPuRERERERERERERDqyc+dOAFBJqsfGxgIA5HI59PX1i23H398fAHDu3DmdxFV4+28CRS//rl27lnMkJcNJU4mIiIiIiIiIiIheQX5+PhISEjB37lwcOnQIXbt2Ra9evZTWSU1NBQA4ODho1aaih3xKSopOYlRs397eXm35xIkT8eDBA6Vl3bp1Q7du3VTWbdmypcbtjB49GgsXLix1nADw888/Y+/evbCxsdH5OPZljQl3IiIiIiIiIiIiolKQyWQqywYPHoxly5apLavINm7ciOvXryst8/DwUJtwb9euncahXgIDA18pjsOHD2P06NGQyWT47bff4Ozs/ErtvW5MuBMRERERERERERGVQmhoKAAgKysLsbGxuHz5Mn799Vc0bdoUYWFhSuva2dkBAJKTk7VqWzHpauEe6dom8YUQKusrtq+px/y1a9ekf8+aNQtffPGFxvYnTZqEkJCQYuNYvnw5oqOjlZbZ29trnLQ1Li4OXbt2RU5ODn788Ue89957xW6jomHCnYiIiIiIiIiIiKgUIiIilP4/Z84cTJgwASNGjEDLli3h7u4ulfn5+QEomDw1Pz8fenpFT6959uxZAED9+vWlZWZmZgCAjIyMIusqys3NzZW2v3btWsTExBS9UzoUHR2NVatWKS1zd3dXm3BPSEhA27Zt8fjxY4SHh2PUqFGvK0yd4qSpRERERERERERERDowfvx4tG3bFhkZGZg+fbpSmVwuh5OTEx49eoRdu3YV2c7FixcRGxsLExMTpfHSXV1dARQkpzV59uyZ1ItdsT7wv0lcd+zYgadPn5Zsx0opIiICQgiln8TERJX1kpKS0KZNGyQlJWH06NGYNm3aa4mvLDDhTkRERERERERERKQjs2bNAgCsXr0aN2/elJYbGBjg008/BQBMmDABmZmZauvn5+djzJgxAICwsDBUqlRJKpPL5bCwsEBKSgpOnDihtv7WrVsBAF5eXkrjrNetWxft2rVDRkYGxo0b9wp7qFuPHz9Gu3btcP36dQwcOBALFiwo75BeCRPuRERERERERERERDoil8vRrVs3vHjxArNnz1YqGzduHAIDAxEXF4cOHTrg1q1bSuWPHj1C7969sWfPHnh6ekrJewUTExMMHToUADBs2DDcv39fqTw+Ph6TJk0CAHz22Wcqsf3yyy+ws7PD8uXLERYWplIfANLT03H+/PkS73dpZGRkoGPHjrhw4QJ69uyJX3/99Y2bbPZlMqEYQZ8qJF9fXwAFXyMhIiIiIiIiIiJ6XfLz8xEfHw8A8PHx0Tjm+I0ZH7zOsEqt2pSNOmtLkRTWlFqNjY2FXC6HsbExEhISlHqaP378GN26dcOhQ4dgYGCAJk2awNXVFSkpKYiOjkZmZiZ8fX2xfft2uLm5qbSdmZmJDh06ICoqCmZmZggODoaDgwPu3r2LI0eOIDc3F71798a6devUJq///fdfdOvWDVeuXIGBgQH8/f3h7u6OvLw83L17F+fPn0dGRgZcXFywZs0apclRQ0JCEBUVhXbt2int08uWLFkijTdflDFjxmDhwoXQ19dHr169YGhoqHa9l8fKf5m216pCWeZcOWkqERERERERERERkQ75+fnhvffew6ZNmzB//nylnu62trY4ePAgIiMjsWbNGpw+fRrHjx+HlZUVGjVqhF69euHjjz/WmHw2NTXFnj17sGLFCqxbtw6nTp1CWloabGxs0LJlSwwcOBC9evXS2FO8Vq1aiIuLw5o1a7Bp0yacPXsWMTExMDAwgKOjI95991107doVH3zwAUxNTdW2UdwY9AsXLtQq4f748WMAQF5eHtatW6dxveIS7hUJe7hXcOzhTkRERERERERE5aGkvYaJyktF6uHOu4SIiIiIiIiIiIiISAeYcCciIiIiIiIiIiIi0gEm3ImIiIiIiIiIiIiIdIAJdyIiIiIiIiIiIiIiHWDCnYiIiIiIiIiIiIhIB5hwJyIiIiIiIiIiIiLSASbciYiIiIiIiIiIiIh04K1MuGdmZmLq1KmoUaMGTExM4OzsjI8++gh37959pXavXr0KU1NTyGQyvPPOOzqKloiIiIiIiIiIiIjeBG9dwj0rKwutWrXCN998g+fPn6Nr166oWrUqVq5cCblcjhs3bpS67SFDhiA7O1uH0RIRERERERERERHRm+KtS7h/++23OH78OJo0aYIrV64gMjISJ06cwLx585CcnIyPPvqoVO2uWLECBw8exODBg3UcMRERERERERERERG9Cd6qhHtOTg4WL14MAPjpp59gYWEhlY0dOxb16tVDVFQUzpw5U6J2Hzx4gPHjx6NNmzbo06ePTmMmIiIiIiIiIiIiojfDW5VwP3LkCJ4+fYrq1atDLperlHfv3h0AsHXr1hK1O3r0aGRmZmLJkiU6iZOIiIiIiIiIiIiI3jxvVcI9NjYWANCgQQO15Yrl58+f17rN7du3IzIyEpMnT4aXl9erB0lEREREREREREREb6S3KuF+69YtAICrq6vacsXymzdvatVeeno6hg8fDh8fH0ycOFE3QRIREREREREREVGFJpPJlH709PRgbW2Nxo0bY+HChcjNzS2yvhACkZGR6Ny5M5ydnWFsbIzKlSujdevWWLZsmcb6ERERkMlkCAkJKbJ9Dw8PyGQyHDx4UG15bm4uVq5ciS5dusDV1RUmJiYwNzeHl5cXevfujXXr1iE7O1ulXkhIiMq+v/zj4eFRZGyFJSYmlrhORWdQ3gG8Ts+fPwcAmJmZqS03NzcHAKSlpWnV3pdffombN2/iwIEDMDIyeqXYfH191S6/fv06qlev/kptExERERERERERke6FhoYCAPLy8pCYmIijR4/ixIkT+Oeff7Bz504YGKimXx8/foz33nsPUVFR0NfXR5MmTRASEoLk5GRER0dj//79WLx4MbZt2wY3Nzedx3z58mV069YN8fHxMDAwgL+/P4KCgpCXl4ebN29i/fr1iIyMxMSJE3H+/HnY2tqqtNGuXTs4OTmpbd/e3l7nMb9J3qqEuy6dPn0aP/74Iz788MNi3ygRERERERERERH9V/WM/KS8Q9DKX72W6rzNiIgIpf+fOHECISEh2LdvH/7880/0799fqTw3Nxft27fHyZMn0axZM6xevRru7u5SeWpqKoYOHYqNGzciJCQEMTExsLa21lm8t27dQnBwMFJTUxEaGorvv/8ejo6OSuukpKRgyZIlmD17NtLT09Um3CdNmsScqAZv1ZAyFhYWAICMjAy15enp6QAAS0vLItt58eIFBg8eDBsbG8ydO1cnsV28eFHtD3u3ExERERERERERvRkaNWqEsLAwAMCuXbtUyufNm4eTJ0+idu3a2Llzp1KyHQDs7OwQGRmJVq1aISEhAZMmTdJpfEOGDEFqaioGDRqEiIgIlWQ7UNBDferUqTpP9r8t3qoe7oqvYNy5c0dtuWL5yxe6uvXOnTsHJycn9OjRQ6nsyZMnAIAzZ85Ib3k0jZVERERERERERERE/y2KoaMfPnyotPzFixf48ccfAQCzZ8/WOOy1vr4+fvjhB9StWxcRERGYMWMGKlWq9MpxxcXFYdeuXTAzM9OqE7G3t/crb/Nt9FYl3P38/AAAZ8+eVVuuWF6vXj2t2rt//z7u37+vtuzJkyeIiooqRZRERERERERERET0plLMD1m5cmWl5TExMUhKSkKlSpXQvn37ItuoU6cO6tWrh/Pnz+PAgQP44IMPXjmuHTt2AAA6dOjAnutl6K0aUiYoKAjW1ta4fv06zp07p1K+YcMGAEDnzp2LbMfDwwNCCLU/Bw4cAAC0bt1aWkZERERERERERERvh507dwKASlI9NjYWACCXy6Gvr19sO/7+/gCgNo9ZGoW3T2XnrUq4GxkZYeTIkQCAESNGSGO2A8D8+fNx/vx5tGjRQrqYAWDx4sWoWbMmvvjii9ceLxEREREREREREVV8+fn5uH79Oj755BMcOnQIXbt2Ra9evZTWSU1NBQA4ODho1aaih3xKSopOYlRs397eXm35xIkTERYWpvSzZcsWteu2bNkSMplM7c9nn32mk3jfVG/VkDIA8OWXX2Lv3r04evQovL290axZM9y8eRMnTpyAg4MDfvvtN6X1U1JSEB8fj6SkpHKKmIiIiIiIiIiIiCoimUymsmzw4MFYtmyZ2rKKbOPGjbh+/brSMg8PD3Tr1k1l3Xbt2sHJyUltO4GBgWUR3hvjrUu4m5iY4MCBA5g5cybWrVuHLVu2oFKlSggLC8M333wDV1fX8g6RiIiIiIiIiIiI3gChoaEAgKysLMTGxuLy5cv49ddf0bRpU4SFhSmta2dnBwBITk7Wqm3FpKuFe6Rrm8RXDHNdeH3F9jX1mL927Zr071mzZhU54sekSZMQEhJSbBzLly9HdHS00jJ7e3utJm19U711CXcAMDU1xddff42vv/662HXDw8MRHh6uddshISEct52IiIiIiIiIiOgtEBERofT/OXPmYMKECRgxYgRatmwJd3d3qczPzw9AweSp+fn50NMrerTvs2fPAgDq168vLTMzMwMAZGRkFFlXUW5ubq60/bVr1yImJqbondKh6OhorFq1SmmZu7v7fzrh/laN4U5ERERERERERERUVsaPH4+2bdsiIyMD06dPVyqTy+VwcnLCo0ePsGvXriLbuXjxImJjY2FiYoKWLVtKyxWjcyQkJGis++zZM6kXe+HRPBSTuO7YsQNPnz4t2Y6VUkREBIQQSj+JiYmvZdvlhQl3IiIiIiIiIiIiIh2ZNWsWAGD16tW4efOmtNzAwACffvopAGDChAnIzMxUWz8/Px9jxowBAISFhaFSpUpSmVwuh4WFBVJSUnDixAm19bdu3QoA8PLyUhpnvW7dumjXrh0yMjIwbty4V9hDKgoT7kREREREREREREQ6IpfL0a1bN7x48QKzZ89WKhs3bhwCAwMRFxeHDh064NatW0rljx49Qu/evbFnzx54enpKyXsFExMTDB06FAAwbNgw3L9/X6k8Pj4ekyZNAgB89tlnKrH98ssvsLOzw/LlyxEWFqZSHwDS09Nx/vz5Eu83FZAJDjheofn6+gIo+BoJERERERERERHR65Kfn4/4+HgAgI+Pj8Yxx3tGfvI6wyq1v3ot1VlbislINaVWY2NjIZfLYWxsjISEBKWe5o8fP0a3bt1w6NAhGBgYoEmTJnB1dUVKSgqio6ORmZkJX19fbN++HW5ubiptZ2ZmokOHDoiKioKZmRmCg4Ph4OCAu3fv4siRI8jNzUXv3r2xbt06tZOs/vvvv+jWrRuuXLkCAwMD+Pv7w93dHXl5ebh79y7Onz+PjIwMuLi4YM2aNUqTo4aEhCAqKgrt2rVT2qeXLVmyRBpvviiJiYnw9PSEkZER5HK5xvW++uordOzYUWO5tteqQlnmXN/KSVOJzp07h1GjRuH06dNwcnLC559/jpEjRxZZZ/v27ZgxYwYuX76MjIwMVKtWDZ988glGjBghPbzCw8NVxudSWLduHfr06YNnz55hzpw52L59O65cuQJbW1u0b98eM2fOlGaLJiIiIiIiIiKiN5efnx/ee+89bNq0CfPnz1fq6W5ra4uDBw8iMjISa9aswenTp3H8+HFYWVmhUaNG6NWrFz7++GMYGhqqbdvU1BR79uzBihUrsG7dOpw6dQppaWmwsbFBy5YtMXDgQPTq1Uttsh0AatWqhbi4OKxZswabNm3C2bNnERMTAwMDAzg6OuLdd99F165d8cEHH8DU1FRtG8WNQb9w4UKtEu4KOTk5GofIAYDk5GSt2ypv7OFewbGHu+4lJyejdu3aCAwMxNixY3H27Fl88cUXWLlyJQYMGKCx3po1a/Dvv/8iICAAVlZWiIqKwrfffot58+ZJX9G5c+cO7ty5o1Tvt99+w2+//YakpCQ4ODhIXxkaMmQIgoKCcP/+fXz11VdwdHTE4cOHoa+vX5a7T0RERERERESklZL2GiYqLxWphzsT7hUcE+66980332DRokVITEyU3rQNHz4ce/fuxZUrV0rUVv/+/REfH49Tp05pXCcgIAC2trbYvXs3gIJxsPT09JTeEJ44cQKNGzfGkSNH0LRp01LsFRERERERERGRbjHhTm+KipRw511Cb51du3bh3XffVfpaS48ePXD16lXcuHGjRG3Z2dkhNzdXY/mNGzdw+vRp9OrVS1pmbm6u8nWcevXqAQASEhJKtH0iIiIiIiIiIiKqOJhwp7fOlStXULNmTaVliv8r3oQVJS8vD+np6di9ezdWr16N4cOHa1w3MjIShoaGeO+994ps89ixYwAALy+vYrdPREREREREREREFRMnTaW3zuPHj2FjY6O0zNbWViorjrm5ObKzswEAX375JYYMGaJx3cjISLRp0waVKlXSuM6LFy8wadIkBAYGolGjRlrsAREREREREREREVVETLgTldDRo0eRnp6OQ4cOYcaMGbCzs5MmTS0sPj4esbGxGDt2bJHtjR8/HpcuXcLx48fLKGIiIiIiIiIiIiJ6HZhwp7eOra0tnj59qrTsyZMnUllxGjRoAABo1qwZgIJe7iNGjIChoaHSen/99ReMjY3RtWtXjW0tXboUP/74IzZv3ow6deqUZDeIiIiIiIiIiIioguEY7vTWqVGjBi5fvqy0TPF/Hx+fErVVv359pKen48GDByplkZGRaN++PaytrdXW3b59O0aNGoU5c+agS5cuJdouERERERERERERVTxMuNNbp127dti+fTsyMzOlZRs2bIC3tzeqVatWoraOHj0KMzMzVK5cWWn5xYsXcfHiRfTq1UttvZiYGPTq1QtDhgwpdsgZIiIiIiIiIiIiejNwSBl66wwbNgw//vgjevbsic8++wwxMTFYtmwZfvvtN6X1DAwMMHXqVEydOhUA0L17dzRu3Fga+mX//v1YsGABJkyYACMjI6W6kZGRMDU1RefOnVW2/+DBA3Tq1AkuLi7o16+f0tjtrq6ucHV11fUuExERERERERGVmEwmk/6dn58PPT323aWKKT8/X/p34eu2PDDhTm8dBwcH7NmzByNHjkTHjh3h6OiI+fPnY8CAAUrr5eXlKd2s/v7+WLVqFRISEmBoaAhvb2+sWLFCpR5QMH57x44dYWFhoVL277//4t69ewCA4OBgpbJp06YhPDxcB3tJRERERERERPRqZDIZjIyMkJOTg/T0dI3D5hKVt/T0dACAkZFRuSfcZUIIUa4RUJF8fX0BFAxRQkRERERERERE9Do9fPgQqamp0NfXh6OjI8zNzdnTnSqM/Px8aX7FvLw82NnZqQz9rE5Z5lzZw52IiIiIiIiIiIjUsrOzQ3p6OrKysqRv7BNVRCYmJrCzsyvvMJhwJyIiIiIiIiIiIvX09fXh5uaG1NRUpKWlIScnp7xDIlJiZGQES0tL2NnZQV9fv7zDYcKdiIiIiIiIiIiINNPX10flypVRuXJlCCHAEaqpopDJZOU+ZvvLmHAnIiIiIiIiIiIirVTEBCdRRcIZDoiIiIiIiIiIiIiIdIAJdyIiIiIiIiIiIiIiHWDCnYiIiIiIiIiIiIhIB5hwJyIiIiIiIiIiIiLSAU6aShVa58//r7xD+M/YOq9reYdARERERERERET0n8Ye7kREREREREREREREOsCEOxERERERERERERGRDjDhTkRERERERERERESkA0y4ExERERERERERERHpABPuREREREREREREREQ6wIQ7EREREREREREREZEOMOFORERERERERERERKQDTLgTEREREREREREREekAE+5ERERERERERERERDrAhDsRERERERERERERkQ4w4U5EREREREREREREpANMuBMRERERERERERER6QAT7kREREREREREREREOsCEOxERERERERERERGRDjDhTkRUgZw7dw7NmjWDqakpPD09sXjx4mLrbN++HUFBQbCzs4OpqSl8fX2xePFiCCHUrp+ZmQkPDw/IZDJcu3ZNWv706VO89957qFq1KkxMTODi4oKBAwciKSlJZ/tHRERERERERPRfZlDeARARUYHk5GS0adMGgYGB+Oeff3D27Fl89tlnsLa2xoABAzTWe/To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sd2JiIiIiIiIiIiIiCqackm437hxA0ZGRqhfv36x68pkMlhZWeHZs2dlHxgRERERERERERERUSmVS8I9Pz8fBgYGKpOkqiOEwPPnz2Fubv4aIiMiIiIiIiIiIiIiKp1ySbi7uLggIyMDDx8+LHbdU6dOITs7G56enq8hMiIiIiIiIiIiIiKi0imXhHtISAgAYOXKlcWuO336dMhkMrRp06aMoyIiIiIiIiIiIiIiKr1ySbiPHj0aMpkM3333Hfbu3at2nQcPHqBfv37YsWMHjIyMMGLEiNccJRERERERERERERGR9sol4e7r64vvvvsOaWlpaNeuHRo2bIinT58CAPr27YugoCC4u7vjzz//BAD88MMPcHNzK49QiYiIiIiIiIiIiIi0YlBeG54wYQLs7Owwbtw4nD17VloeGRkJIQQAwMbGBgsXLsSHH35YXmESEREREREREREREWml3BLuAPDxxx+jV69e2LhxI44cOYJ79+4hLy8PTk5OCAoKQo8ePWBtbV2eIRIRERERERERERERaaVcEu6HDh0CANSrVw82NjYIDQ1FaGhoeYRCRERERERERERERKQT5ZJwDwkJgb6+Ph4+fFgemyciIiIiIiIiIiIi0rlySbhbW1tDX18ftra25bF5IiIiIiIiIiIiIiKd0yuPjXp5eSEtLQ3Z2dnlsXkiIiIiIiIiIiIiIp0rl4R77969kZubi7/++qs8Nk9EREREREREREREpHPlknAfPXo0mjRpgpEjR2L79u3lEQIRERERERERERERkU6Vyxju3333HZo3b44LFy6gc+fO8PX1RVBQECpXrgx9fX2N9aZOnfoaoyQiIiIiIiIiIiIi0l65JNzDw8Mhk8kghAAAxMXF4eLFi8XWY8L9/7F353E21v//x59nZpiVmbHvY6fIHtkHyWSJrPHJklS2NGVrsQyjpKRIoYQiWQYV2RmyRJgQ2WYYW5YRhtkYM9fvj37nfJ1mMWPOnDN43G+3c7s57+v9fl+v68jVmedc1/sCAAAAAAAAAORUDgncmzRpIpPJ5IhdAwAAAAAAAACQLRwSuG/ZssURu7WIj4/XxIkTtWjRIp05c0b58uVTQECAgoODVbx48QzNcefOHU2YMEF79uzRkSNHFBUVpcTERJUsWVItW7bUyJEj5efnl81HAgAAAAAAAADIKRzy0FRHSkhIUPPm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mK5cuaKWLVuqcOHCKca4u7urdu3a+uWXX3TixAlVqlTpvo/pxRdftHrv6empHj16qFmzZnriiSf0448/ateuXXrqqafuex8AYAuenp7q3Lmzo8uweu7E3bc8mzVs2FDly5dP0V6jRo3sLAvAQ2j9+vWSpA4dOqS6LIN5/ebff//dqt3Z2VkLFixQjRo1NGzYMN25c0f58+fX3LlzUz1vmZUpUyZF27PPPquffvpJuXLlSnXMiRMntHr1aoWHhys2NlbJycmW8+SJEydSHePv76/cuXNbtbm4uKhMmTIKCwvTP//8k+J2/jt37qh3796aP3++WrVqpeXLl8vDwyPNYwEeFC1atFB4eLh++eUXrV+/Xr///rsOHjyo69eva8aMGVq2bJl+/fVXVapU6b7PCZKUK1cuNWvWLEV7xYoVJSlT61Zv2bJFiYmJCggISHUpjyJFiqhChQr6888/FR8fn6JPastGpVbHli1blJSUpLZt28rPz++edZk/n44dO6a6vXHjxpo2bZp+//13Pf/88/ecLzXPPfdcutvPnz+vlStX6ujRo7px44aSk5MlSblz507znFi7dm3lz58/RXvFihV16NAhXbhwwbJ+fu3atbVmzRoNGjRIEyZMUKNGjTK9TK4kS07RtWvXVM/vPXv21PLlyy397la0aFHVqVMn3flT+zs2P7g1vW13//1nNRdJ6+/KVp8hbI+/BeABZ/6fmfkhNRn1999/S1KKh8WY+fj4yNvbW9HR0bp27Zry589vGZPWF4TU5jI/xGTDhg3p/lAkybLemq0VLVpUL730kiZPnqy1a9feV+D+1FNPqUOHDoqLi9OePXu0fv16JSUl2bxWAI+GAgUKaN68een2uXLlioYNG5aivV+/fpa1LLPqypUrlj//d71K87769Oljk30BeLSZvxO+9957eu+999Lsl5CQkKKtbNmymjBhgt544w1J0pdffqlixYqlu79OnTrJy8tLt2/f1rFjxxQWFqY1a9bogw8+0NixY636GoahYcOG6dNPP7X6ReTdzOu//1eJEiVSbc+TJ48kpfrA1cWLF+vOnTuqXr26Vq5cmeYvAIAHUe7cufX8889bQuDr169r0aJFevfdd3X58mUNHjxYGzZsyNI5oUiRIqleAJbev7u0mOv4+uuv9fXXX6fb9+rVqypevLhVW2rngNTqMK+5ndFnNJjr+u/+/uvu73KZVapUqTS3TZkyRW+//bYSExMzNWdmzonDhw/X9u3btWXLFjVr1kxeXl6qX7++2rRpoz59+sjb2ztD+7xXtmFuP3/+fIpt6X0GZqn9HZjXjk9v293HmtVcJK06bfUZwvYI3IEHXI0aNbRjxw6FhYWluMI7q+71P4KMMP8WvHz58mrYsGG6fVP7TbitVKhQQVLmrna428svv2z1gJe///5b33//vZYvX64TJ07oxo0bKlasmNXDdwAgK2JiYvTtt9+maPf397dZ4P7HH39I+vccSeADIDuZvxM2atQo0w8FTU5OVkhIiOX93r171bVr13THTJ482Sp8Wbx4sbp3767x48crICBA9erVs9o2ZcoUlSxZUp9++qnq16+vggULKleuXLp9+7ZcXV3TDOJTuzL3Xho1aqTw8HAdOHBAX3zxhQIDAzM9B/Cg8PHxUf/+/VWsWDG1b99eoaGhiouLy9I54X7+3aXFXEeNGjVUvXr1dPum9oBmW9aSWl13PyA0NXefyzLLzc0t1fZdu3Zp6NCh8vb2tjwQtkiRIpbjL1asWJo/V2fm88ibN682b96sHTt2aOXKldqyZYs2b96sDRs2aOLEidq2bZvl5/isSC/XSOszuFt6x5TR481qLpJWnfb6DJF5BO7AA65Nmzb64osvtHTpUn300UcZvn3IfFXQ6dOnU90eHR2t69evy93d3XLVo/l22LTGpNZu/g135cqV73k1Z3a6du2apH+XcbCFYsWKafjw4Ro+fLhN5gOA/ypdunSaAY+tLF68WJJSvS0bAGzJ/J2wQ4cOGjp0aKbGTpo0Sdu2bZO/v7/Cw8P1ySefqHXr1vL398/wHN26ddPmzZv11Vdf6Z133tHmzZst21asWCFJmjFjhtq0aWM17uTJk5mqNSP8/Pz09ddfy9/fX2+++aacnZ31+uuv23w/QE7SvHlzSVJSUpKuX7+epXOCLZnraNSokT7//PNs20/JkiUlSRERERmuKyIiQp988km2XpiWGvM58f33308R+MfHx+vixYs225fJZFKjRo0sF5NcvnxZgYGB+uGHH/Tee+9pyZIl95zjXtlGRu8WyE7ZmYvY4jOE7WXPr+IA2E1AQICqVKmic+fO6f3330+3740bN3T48GFJ/6715e7urn379qW6/tqCBQsk/bt+r/m3to0bN5YkLVu2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",
            "text/plain": [
              "<IPython.core.display.Image object>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Chart saved to rouge_comparison.png\n"
          ]
        }
      ],
      "source": [
        "from IPython.display import Image as IPyImage, display\n",
        "\n",
        "models  = agg[\"Model\"].tolist()\n",
        "r1      = agg[\"ROUGE-1\"].tolist()\n",
        "r2      = agg[\"ROUGE-2\"].tolist()\n",
        "rL      = agg[\"ROUGE-L\"].tolist()\n",
        "\n",
        "x       = np.arange(len(models))\n",
        "width   = 0.25\n",
        "\n",
        "fig, ax = plt.subplots(figsize=(10, 5))\n",
        "bars1 = ax.bar(x - width, r1, width, label=\"ROUGE-1\", color=\"#4C72B0\")\n",
        "bars2 = ax.bar(x,         r2, width, label=\"ROUGE-2\", color=\"#DD8452\")\n",
        "bars3 = ax.bar(x + width, rL, width, label=\"ROUGE-L\", color=\"#55A868\")\n",
        "\n",
        "ax.set_xlabel(\"Model\", fontsize=12)\n",
        "ax.set_ylabel(\"ROUGE F-measure\", fontsize=12)\n",
        "ax.set_title(\n",
        "    f\"Summarization Model Comparison  |  eval_n={len(eval_data):,}, TOP_N={TOP_N}\\n\"\n",
        "    \"(βš‘ CodeT5 = supervised reference, fine-tuned on the train split)\",\n",
        "    fontsize=11,\n",
        ")\n",
        "ax.set_xticks(x)\n",
        "ax.set_xticklabels(models, fontsize=10)\n",
        "ax.legend(fontsize=10)\n",
        "y_max = max(r1 + r2 + rL) * 1.25 if max(r1 + r2 + rL) > 0 else 1.0\n",
        "ax.set_ylim(0, y_max)\n",
        "\n",
        "for bars in (bars1, bars2, bars3):\n",
        "    for bar in bars:\n",
        "        h = bar.get_height()\n",
        "        ax.annotate(f\"{h:.3f}\",\n",
        "                    xy=(bar.get_x() + bar.get_width() / 2, h),\n",
        "                    xytext=(0, 3), textcoords=\"offset points\",\n",
        "                    ha=\"center\", va=\"bottom\", fontsize=7)\n",
        "\n",
        "plt.tight_layout()\n",
        "plt.savefig(\"rouge_comparison.png\", dpi=150)\n",
        "plt.close(fig)\n",
        "display(IPyImage(\"rouge_comparison.png\"))\n",
        "print(\"Chart saved to rouge_comparison.png\")"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "975fd8fd",
      "metadata": {},
      "source": [
        "---\n",
        "## Section 10 β€” Save Results"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 27,
      "id": "90aa9110",
      "metadata": {
        "execution": {
          "iopub.execute_input": "2026-06-15T13:47:06.002103Z",
          "iopub.status.busy": "2026-06-15T13:47:06.001996Z",
          "iopub.status.idle": "2026-06-15T13:47:06.013080Z",
          "shell.execute_reply": "2026-06-15T13:47:06.012272Z"
        }
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Saved:\n",
            "  per_sample_results.csv  β€” per-row predictions and ROUGE scores\n",
            "  aggregate_comparison.csv β€” mean ROUGE-1/2/L per model\n"
          ]
        }
      ],
      "source": [
        "results_df.to_csv(\"per_sample_results.csv\", index=False)\n",
        "agg.to_csv(\"aggregate_comparison.csv\", index=False)\n",
        "print(\"Saved:\")\n",
        "print(\"  per_sample_results.csv  β€” per-row predictions and ROUGE scores\")\n",
        "print(\"  aggregate_comparison.csv β€” mean ROUGE-1/2/L per model\")"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": ".venv",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.10.9"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}