PageSourceSearch

https://www.minizinc.org/challenge/scoring.js

js minizinc.org collected 2026-09-24 09:29:05 UTC 46,410 bytes, 1,228 lines download raw bytes

1function challengeResults({
2    results: {
3        nb_s,
4        nb_p,
5        solvers,
6        fd_solvers,
7        free_solvers,
8        par_solvers,
9        open_solvers,
10        local_solvers,
11        problems,
12        kind,
13        instances,
14        benchmarks,
15        results,
16        times,
17        objectives,
18        first_objectives,
19        step_count,
20        step_obj,
21        step_times,
22        scores,
23        scores_loc
24    },
25    locations: {
26        problems: loc_problems,
27        instances: loc_instances
28    }
29}) {
30    const max_time_in_ms = 1200000;
31    const pbox = {};
32    const sbox = {};
33
34    // Complete Scoring
35    let total = 0;
36    const total_solver = []; // Total overall score of a solver
37    const total_problem = [];
38    const total_instance = [];
39    const total_solver_instance = []; // Total score of a solver per instance
40    const total_solver_problem = []; // Total score of a solver per problem
41
42    // Incomplete Scoring
43    const hasIncompleteScoring = scores_loc !== undefined;
44    let total_inc = 0;
45    const total_solver_inc = []; // Total overall score of a solver
46    const total_problem_inc = [];
47    const total_instance_inc = [];
48    const total_solver_instance_inc = []; // Total score of a solver per instance
49    const total_solver_problem_inc = []; // Total score of a solver per problem
50
51    // Area Scoring
52    const hasAreaScoring = step_count !== undefined;
53    let total_area = 0;
54    const total_solver_area = []; // Total overall score of a solver
55    const total_problem_area = [];
56    const total_instance_area = [];
57    const total_solver_instance_area = []; // Total score of a solver per instance
58    const total_solver_problem_area = []; // Total score of a solver per problem
59
60    const rank_solver = [];
61    const rank_problem_solver = [];
62    const map_problem_solver_rank = [];
63
64    function init() {
65        const p1 = document.getElementById("solver_selection");
66        while (p1.firstChild) {
67            p1.removeChild(p1.lastChild)
68        }
69        const f1 = document.createElement('form');
70        f1.name = "solver_checked";
71        for (let i = 0; i < nb_s; i++) {
72            sbox[i] = document.createElement("input");
73            sbox[i].id = `solver-checkbox-${i}`
74            sbox[i].type = 'checkbox';
75            sbox[i].name = solvers[i];
76            sbox[i].defaultChecked = false;
77            sbox[i].value = i;
78            f1.appendChild(sbox[i]);
79            const label = document.createElement('label');
80            label.htmlFor = `solver-checkbox-${i}`;
81            label.style.paddingLeft = '0.25rem';
82            label.appendChild(document.createTextNode(solvers[i]));
83            f1.appendChild(label);
84            f1.appendChild(document.createElement('br'));
85        }
86        if (p1 != null)
87            p1.appendChild(f1);
88        const p2 = document.getElementById("problem_selection");
89        while (p2.firstChild) {
90            p2.removeChild(p2.lastChild)
91        }
92        const f2 = document.createElement('form');
93        f2.name = "problem_checked";
94        for (let i = 0; i < nb_p; i++) {
95            pbox[i] = document.createElement("input");
96            pbox[i].id = `problem-checkbox-${i}`
97            pbox[i].type = 'checkbox';
98            pbox[i].name = problems[i];
99            pbox[i].defaultChecked = false;
100            pbox[i].value = i;
101            f2.appendChild(pbox[i]);
102            const label = document.createElement('label');
103            label.htmlFor = `problem-checkbox-${i}`;
104            label.style.paddingLeft = '0.25rem';
105            label.appendChild(document.createTextNode(problems[i]));
106            f2.appendChild(label)
107            f2.appendChild(document.createElement('br'));
108        }
109        if (p2 != null)
110            p2.appendChild(f2);
111        for (let i = 0; i < nb_s; i++) {
112            total_solver_problem[i] = [];
113            total_solver_instance[i] = [];
114            total_solver_problem_inc[i] = [];
115            total_solver_instance_inc[i] = [];
116            total_solver_problem_area[i] = [];
117            total_solver_instance_area[i] = [];
118        }
119
120        const classControls = [
121            [fd_solvers, document.getElementById("control-fd")],
122            [free_solvers, document.getElementById("control-free")],
123            [par_solvers, document.getElementById("control-par")],
124            [open_solvers, document.getElementById("control-open")],
125            [local_solvers, document.getElementById("control-local")]
126        ];
127        let prevSolvers = null;
128        for (const [s, e] of classControls) {
129            if (s.every(x => !x) || prevSolvers && prevSolvers.every((x, i) => (s[i] === x))) {
130                e.style.display = 'none';
131            }
132            prevSolvers = s;
133        }
134        if (!hasIncompleteScoring) {
135            for (const el of document.getElementsByClassName('score-incomplete')) {
136                el.style.display = 'none';
137            }
138        }
139        if (!hasAreaScoring) {
140            for (const el of document.getElementsByClassName('score-area')) {
141                el.style.display = 'none';
142            }
143        }
144    }
145
146    function selectCategory(category) {
147        for (let i = 0; i < nb_s; i++) {
148            if (category[i] && !sbox[i].disabled) {
149                sbox[i].checked = true;
150            }
151        }
152    }
153
154    function selectFD() {
155        selectCategory(fd_solvers);
156    }
157
158    function selectFree() {
159        selectCategory(free_solvers);
160    }
161
162    function selectPar() {
163        selectCategory(par_solvers);
164    }
165
166    function selectOpen() {
167        selectCategory(open_solvers);
168    }
169
170    function selectLocal() {
171        selectCategory(local_solvers);
172    }
173
174    function selectAll() {
175        for (let i = 0; i < nb_p; i++) {
176            pbox[i].checked = true;
177        }
178    }
179
180    function clearAll() {
181        for (let i = 0; i < nb_p; i++)
182            pbox[i].checked = false;
183        for (let i = 0; i < nb_s; i++)
184            sbox[i].checked = false;
185    }
186
187    function computeSelected() {
188        document.getElementById('results-section').style.display = 'block';
189        const prob = [];
190        const solv = [];
191        for (let i = 0; i < nb_p; i++) {
192            prob[i] = pbox[i].checked;
193        }
194        for (let i = 0; i < nb_s; i++) {
195            solv[i] = sbox[i].checked;
196        }
197        computeScores(solv, prob);
198        if (hasIncompleteScoring) {
199            computeScoresInc(solv, prob);
200        }
201        if (hasAreaScoring) {
202            computeScoresArea(solv, prob);
203        }
204        rankSolvers(solv, prob);
205        modifyTables(solv, prob);
206    }
207
208    function computeScores(selected_s, selected_p) {
209        total = 0.0;
210        for (let s = 0; s < nb_s; s++) {
211            if (!selected_s[s])
212                continue;
213            let ts = 0.0;
214            for (let p = 0; p < nb_p; p++) {
215                if (!selected_p[p])
216                    continue;
217                let tsp = 0.0;
218                for (let k = 0; k < instances[p].length; k++) {
219                    const i = instances[p][k];
220                    let tsi = 0.0;
221                    for (let s2 = 0; s2 < nb_s; s2++) {
222                        if (selected_s[s2])
223                            tsi += scores[s][s2][i]
224                    }
225                    total_solver_instance[s][i] = tsi;
226                    tsp += tsi;
227                }
228                total_solver_problem[s][p] = tsp;
229                ts += tsp;
230            }
231            total_solver[s] = ts;
232            total += ts;
233        };
234        for (let p = 0; p < nb_p; p++) {
235            if (selected_p[p]) {
236                let tp = 0.0;
237                for (let k = 0; k < instances[p].length; k++) {
238                    const i = instances[p][k];
239                    let ti = 0.0;
240                    for (let s = 0; s < nb_s; s++) {
241                        if (selected_s[s])
242                            ti += total_solver_instance[s][i];
243                    }
244                    total_instance[i] = ti;
245                    tp += ti;
246                }
247                total_problem[p] = tp;
248            }
249        }
250    }
251
252    function computeScoresInc(selected_s, selected_p) {
253        total_inc = 0.0;
254        for (let s = 0; s < nb_s; s++) {
255            if (!selected_s[s])
256                continue;
257            let ts = 0.0;
258            for (let p = 0; p < nb_p; p++) {
259                if (!selected_p[p])
260                    continue;
261                let tsp = 0.0;
262                for (let k = 0; k < instances[p].length; k++) {
263                    const i = instances[p][k];
264                    let tsi = 0.0;
265                    for (let s2 = 0; s2 < nb_s; s2++) {
266                        if (selected_s[s2])
267                            tsi += scores_loc[s][s2][i]
268                    }
269                    total_solver_instance_inc[s][i] = tsi;
270                    tsp += tsi;
271                }
272                total_solver_problem_inc[s][p] = tsp;
273                ts += tsp;
274            }
275            total_solver_inc[s] = ts;
276            total_inc += ts;
277        };
278        for (let p = 0; p < nb_p; p++) {
279            if (selected_p[p]) {
280                let tp = 0.0;
281                for (let k = 0; k < instances[p].length; k++) {
282                    const i = instances[p][k];
283                    let ti = 0.0;
284                    for (let s = 0; s < nb_s; s++) {
285                        if (selected_s[s])
286                            ti += total_solver_instance_inc[s][i];
287                    }
288                    total_instance_inc[i] = ti;
289                    tp += ti;
290                }
291                total_problem_inc[p] = tp;
292            }
293        }
294    }
295
296    // Area scoring
297    //
298    function computeScoresArea(selected_s, selected_p) {
299        total_area = 0.0;
300        let normalise = false;
301        if (document.getElementById("area_scoring").checked) {
302            normalise = true;
303        }
304        // Iterating over the problems
305        for (let p = 0; p < nb_p; p++) {
306            // Check if the problem is selected
307            if (!selected_p[p])
308                continue;
309            // Problem is selected
310
311            // Iterating over the instances
312            for (let ii = 0;
312 ii < instances[p].length; ii++) {
313                const i = instances[p][ii];
314
315                // Computing the scores for the instance for each solver
316                if (kind[p] == "SAT") {
317                    computeScoresArea_for_instance_sat(selected_s, p, i, normalise);
318                } else if (kind[p] == "MIN") {
319                    computeScoresArea_for_instance_min(selected_s, p, i, normalise);
320                } else if (kind[p] == "MAX") {
321                    computeScoresArea_for_instance_max(selected_s, p, i, normalise);
322                }
323
324                // Aggregate results for the instance
325                let ti = 0;
326                for (let s = 0; s < nb_s; s++) {
327                    if (selected_s[s]) {
328                        ti += total_solver_instance_area[s][i];
329                    }
330                }
331                total_instance_area[i] = ti;
332            }
333
334            // Aggregate results for the problem
335            let tp = 0;
336            for (let ii = 0; ii < instances[p].length; ii++) {
337                const i = instances[p][ii];
338                tp += total_instance_area[i];
339            }
340            total_problem_area[p] = tp;
341        }
342
343        // Aggregate remaining results for the solvers
344        for (let s = 0; s < nb_s; s++) {
345            if (selected_s[s]) {
346                let ts = 0;
347                for (let p = 0; p < nb_p; p++) {
348                    if (selected_p[p]) {
349                        let tsp = 0;
350                        for (let ii = 0; ii < instances[p].length; ii++) {
351                            const i = instances[p][ii];
352                            tsp += total_solver_instance_area[s][i];
353                        }
354                        total_solver_problem_area[s][p] = tsp;
355                        ts += tsp;
356                    }
357                }
358                total_solver_area[s] = ts;
359                total_area += ts;
360            }
361        }
362    }
363
364    // Computation of the area score for an instance that is unsatisfiable or
365    // belongs to sat problem
366    //
367    function computeScoresArea_for_instance_sat(selected_s, p, i, normalise) {
368        for (let s = 0; s < nb_s; s++) {
369            let area = 0;
370            // Check if the solver is selected
371            if (selected_s[s]) {
372                // Solver is selected
373
374                // Compute the area below the two step function
375                area = 1 * times[s][i] + 0 * (max_time_in_ms - times[s][i]);
376                if (normalise) {
377                    area = area / max_time_in_ms;
378                }
379                // Saving the value
380                total_solver_instance_area[s][i] = area;
381            }
382        }
383    }
384
385    // Computation of the area score for an instance that belongs to a minimisation problem
386    //
387    function computeScoresArea_for_instance_min(selected_s, p, i, normalise) {
388        let min_obj = 0;
389        let max_obj = 0;
390        let sol = false;
391        const scale_unsol = 0.25;
392        const scale_proof = 0.25;
393        const scale_sol = 1 - scale_unsol - scale_proof;
394        // Computing the minimal and maximal objective value
395        for (let s = 0; s < nb_s; s++) {
396            // Check if the solver is selected
397            if (selected_s[s]) {
398                // Solver is selected
399                if (step_count[s][i] > 0) {
400                    if (sol) {
401                        min_obj = Math.min(min_obj, objectives[s][i]);
402                        max_obj = Math.max(max_obj, first_objectives[s][i]);
403                    } else {
404                        min_obj = objectives[s][i];
405                        max_obj = first_objectives[s][i];
406                        sol = true;
407                    }
408                }
409            }
410        }
411        // Computng the area score
412        if (sol) {
413            // At least one solver found a feasible solution
414            for (let s = 0; s < nb_s; s++) {
415                let area = 0;
416                // Check if the solver is selected
417                if (selected_s[s]) {
418                    // Solver is selected
419                    if (step_count[s][i] > 0) {
420                        // Solver has found at least one solution
421
422                        // First (solution) step
423                        area += scale_unsol * step_times[s][i][0];
424                        // Intermediate steps
425                        let prev_time = 0;
426                        let prev_obj = max_obj;
427                        const scale_obj = max_obj - min_obj;
428                        if (scale_obj > 0) {
429                            for (let k = 0; k < step_count[s][i]; k++) {
430                                area += scale_sol * (((prev_obj - min_obj) / scale_obj) * (step_times[s][i][k] - prev_time));
431                                prev_time = step_times[s][i][k];
432                                prev_obj = step_obj[s][i][k];
433                            }
434                            area += scale_sol * (((prev_obj - min_obj) / scale_obj) * (times[s][i] - prev_time));
435                        } else {
436                            area += scale_sol * step_times[s][i][0];
437                        }
438                        // Last (optimal proof) step
439                        area += scale_proof * times[s][i];
440                    } else {
441                        // Solver has not found any solution
442                        area = 1 * max_time_in_ms;
443                    }
444                    // Normalise area scoring
445                    if (normalise) {
446                        area = area / max_time_in_ms;
447                    }
448                    // Storing area scoring
449                    total_solver_instance_area[s][i] = area;
450                }
451            }
452        } else {
453            // Use the scoring for sat (unsat) instances
454            computeScoresArea_for_instance_sat(selected_s, p, i, normalise);
455        }
456    }
457
458    // Computation of the area score for an instance that belongs to a maximisation problem
459    //
460    function computeScoresArea_for_instance_max(selected_s, p, i, normalise) {
461        let min_obj = 0;
462        let max_obj = 0;
463        let sol = false;
464        const scale_unsol = 0.25;
465        const scale_proof = 0.25;
466        const scale_sol = 1 - scale_unsol - scale_proof;
467        // Computing the minimal and maximal objective value
468        for (let s = 0; s < nb_s; s++) {
469            // Check if the solver is selected
470            if (selected_s[s]) {
471                // Solver is selected
472                if (step_count[s][i] > 0) {
473                    if (sol) {
474                        min_obj = Math.min(min_obj, first_objectives[s][i]);
475                        max_obj = Math.max(max_obj, objectives[s][i]);
476                    } else {
477                        min_obj = first_objectives[s][i];
478                        max_obj = objectives[s][i];
479                        sol = true;
480                    }
481                }
482            }
483        }
484        // Computng the area score
485        if (sol) {
486            // At least one solver found a feasible solution
487            for (let s = 0; s < nb_s; s++) {
488                let area = 0;
489                // Check if the solver is selected
490                if (selected_s[s]) {
491                    // Solver is selected
492                    if (step_count[s][i] > 0) {
493                        // Solver has found at least one solution
494
495                        // First (solution) step
496                        area += scale_unsol * step_times[s][i][0];
497                        // Intermediate steps
498                        let prev_time = 0;
499                        let prev_obj = min_obj;
500                        const scale_obj = max_obj - min_obj;
501                        if (scale_obj > 0) {
502                            for (let k = 0; k < step_count[s][i]; k++) {
503                                area += scale_sol * (((max_obj - prev_obj) / scale_obj) * (step_times[s][i][k] - prev_time));
504                                prev_time = step_times[s][i][k];
505                                prev_obj = step_obj[s][i][k];
506                            }
507                            area += scale_sol * (((max_obj - prev_obj) / scale_obj) * (times[s][i] - prev_time));
508                        } else {
509                            area += scale_sol * step_times[s][i][0];
510                        }
511                        // Last (optimal proof) step
512                        area += scale_proof * times[s][i];
513                    } else {
514                        // Solver has not found any solution
515                        area = 1 * max_time_in_ms;
516                    }
517                    // Normalise area scoring
518                    if (normalise) {
519                        area = area / max_time_in_ms;
520                    }
521                    total_solver_instance_area[s][i] = area;
522                }
523            }
524        } else {
525            // Use the scoring for sat (unsat) instances
526            computeScoresArea_for_instance_sat(selected_s, p, i, normalise);
527        }
528    }
529
530    // Ranking of the solvers corresponding their score
531    //
532    function rankSolvers(selected_s, selected_p) {
533        for (let p = 0; p < nb_p; p++) {
534            rank_problem_solver[p] = [];
535            map_problem_solver_rank[p] = [];
536        }
537        // Initialise arrays
538        for (let s = 0; s < nb_s; s++) {
539            if (selected_s[s]) {
540                rank_solver[s] = {
541                    id: s,
542                    score: total_solver[s]
543                };
544                for (let p = 0; p < nb_p; p++) {
545                    if (selected_p[p])
546                        rank_problem_solver[p][s] = {
547                            id: s,
548                            score: total_solver_problem[s][p],
549                            color: "none"
550                        };
551                }
552            } else {
553                rank_solver[s] = {
554                    id: s,
555                    score: -1.0
556                };
557                for (let p = 0; p < nb_p; p++) {
558                    if (selected_p[p])
559                        rank_problem_solver[p][s] = {
560                            id: s,
561                            score: -1.0,
562                            color: "none"
563                        };
564                }
565            }
566        }
567        // Sorting of the arrays
568        rank_solver.sort((a, b) => b.score - a.score);
569        for (let p = 0; p < nb_p; p++) {
570            if (!selected_p[p])
571                continue;
572            rank_problem_solver[p].sort((a, b) => b.score - a.score);
573            rank_problem_solver[p][0].color = "gold";
574            for (let r = 1; r < nb_s; r++) {
575                if (rank_problem_solver[p][r].score < 0.0)
576                    break;
577                if (rank_problem_solver[p][r - 1].score == rank_problem_solver[p][r].score) {
578                    rank_problem_solver[p][r].color = rank_problem_solver[p][r - 1].color;
579                } else if (r == 1) {
580                    rank_problem_solver[p][r].color = "silver";
581                } else if (r == 2) {
582                    rank_problem_solver[p][r].color = "#cd7f32";
583                } else {
584                    break;
585                }
586            }
587            for (let r = 0; r < nb_s; r++) {
588                var s = rank_problem_solver[p][r].id;
589                map_problem_solver_rank[p][s] = r;
590            }
591        }
592    }
593
594    function createLinkCol(text, loc) {
595        const link = document.createElement('a');
596        link.href = `../${loc}`;
597        link.target = "_blank";
598        link.appendChild(document.createTextNode(text));
599        const col = document.createElement('td');
600        col.appendChild(link);
601        return col;
602    }
603
604    function createTxtCol(text, al) {
605        const col = document.createElement('td');
606        col.align = al;
607        const txt = document.createTextNode(text);
608        col.appendChild(txt);
609        return col;
610    }
611
612    function createTxtColWithColor(text, al, color) {
613        const col = document.createElement('td');
614        col.align = al;
615        col.style.backgroundColor = color;
616        const txt = document.createTextNode(text);
617        col.appendChild(txt);
618        return col;
619    }
620
621
622    // The first n left elements are left aligned, the rest is right aligned
623    function addRowText(table, rowtext, n) {
624        const row = document.createElement('tr');
625        let k = n;
626        for (const i in rowtext) {
627            let al = "right";
628            if (k > 0) {
629                k--;
630                al = "left";
631            }
632            row.appendChild(createTxtCol(`   ${rowtext[i]} `, al));
633        }
634        table.appendChild(row);
635    }
636
637    // The first n left elements are left aligned, the rest is right aligned.
638    // The first m elements have no background color.
639    function addRowTextWithColor(table, rowtext, n, color, m) {
640        const row = document.createElement('tr');
641        let k = n;
642        let l = m;
643        //row.style.backgroundColor = color;
644        for (const i in rowtext) {
645            let al = "right";
646            if (k > 0) {
647                k--;
648                al = "left";
649            }
650            if (l > 0) {
651                row.appendChild(createTxtCol(`   ${rowtext[i]} `, al));
652                l--;
653            } else {
654                row.appendChild(createTxtColWithColor(`   ${rowtext[i]} `, al, color));
655            }
656        }
657        table.appendChild(row);
658    }
659
660    function modifyToTal(selected_solver) {
661        const tbl = document.getElementsByName('total_table')[0];
662        let bd = document.createElement('tbody');
663        const tr = ["TOTAL", total.toFixed(0)];
664        if (hasIncompleteScoring) {
665            tr.push(total_inc.toFixed(0));
666        }
667        if (hasAreaScoring) {
668            tr.push(total_area.toFixed(3));
669        }
670        addRowText(bd, tr, 1);
671        tbl.appendChild(bd);
672        bd = document.createElement('tbody');
673        for (let i = 0; i < nb_s; i++) {
674            if (selected_solver[i]) {
675                let color = "none";
676                if (rank_solver[0].id == i)
677                    color = "gold";
678                if (rank_solver[1].id == i)
679                    color = "silver";
680                if (rank_solver[2].id == i)
681                    color = "#cd7f32";
682                const tr = [solvers[i], total_solver[i].toFixed(2)];
683                if (hasIncompleteScoring) {
684                    tr.push(total_solver_inc[i].toFixed(2));
685                }
686                if (hasAreaScoring) {
687                    tr.push(total_solver_area[i].toFixed(2));
688                }
689                if (color == "none") {
690                    addRowText(bd, tr, 1);
691                } else {
692                    addRowTextWithColor(bd, tr, 1, color, 0);
693                }
694            }
695        }
696        tbl.appendChild(bd);
697    }
698
699    function modifyProblem(selected_solver, selected_problem) {
700        const tbl = document.getElementsByName('problem_table')[0];
701        for (let i = 0; i < nb_p; i++) {
702            if (!selected_problem[i])
703                continue;
704            let bd = document.createElement('tbody');
705            const row = document.createElement('tr');
706            if (loc_problems[i] != 'null') {
707                row.appendChild(createLinkCol(
708                    `${problems[i]} (${kind[i]} x${instances[i].length})`, loc_problems[i]
709                ));
710            } else {
711                row.appendChild(createTxtCol(
712                    `${problems[i]} (${kind[i]} x${instances[i].length})`
713                ));
714            }
715            row.appendChild(createTxtCol("TOTAL", "left"));
716            row.appendChild(createTxtCol(total_problem[i].toFixed(0), "right"));
717            if (hasIncompleteScoring) {
718                row.appendChild(createTxtCol(total_problem_inc[i].toFixed(0), "right"));
719            }
720            if (hasAreaScoring) {
721                row.appendChild(createTxtCol(total_problem_area[i].toFixed(3), "right"));
722            }
723            bd.appendChild(row);
724            tbl.appendChild(bd);
725            bd = document.createElement('tbody');
726            for (let j = 0; j < nb_s; j++) {
727                if (!selected_solver[j])
728                    continue;
729                const rank = map_problem_solver_rank[i][j];
730                const color = rank_problem_solver[i][rank].color;
731                const tr = [" ", solvers[j], total_solver_problem[j][i].toFixed(2)];
732                if (hasIncompleteScoring) {
733                    tr.push(total_solver_problem_inc[j][i].toFixed(2));
734                }
735                if (hasAreaScoring) {
736                    tr.push(total_solver_problem_area[j][i].toFixed(2));
737                }
738                if (color == "none") {
739                    addRowText(bd, tr, 2);
740                } else {
741                    addRowTextWithColor(bd, tr, 2, color, 1);
742                }
743            }
744            tbl.appendChild(bd);
745        }
746    }
747
748    function rankAndMap(ranking, map) {
749        // Sort the array
750        ranking.sort((a, b) => b.score - a.score);
751        // Compute the colors
752        ranking[0].color = "gold";
753        for (let r = 1; r < nb_s; r++) {
754            if (ranking[r].score < 0.0)
755                break;
756            if (ranking[r - 1].score == ranking[r].score) {
757                ranking[r].color = ranking[r - 1].color;
758            } else if (r == 1) {
759                ranking[r].color = "silver";
760            } else if (r == 2) {
761                ranking[r].color = "#cd7f32";
762            } else {
763                break;
764            }
765        }
766        // Create the mapping
767        for (let r = 0; r < nb_s; r++)
768            map[ranking[r].id] = r;
769    }
770
771
772    function modifyInstance(selected_solver, selected_problem) {
773        const tbl = document.getElementsByName('instance_table')[0];
774
775        for (let p = 0; p < nb_p; p++) {
776            if (selected_problem[p]) {
777                for (let k = 0; k < instances[p].length; k++) {
778                    const i = instances[p][k];
779
780                    // Compute the solver ranking
781                    const ranking = [];
782                    const map = [];
783                    for (let s = 0; s < nb_s; s++) {
784                        if (selected_solver[s]) {
785                            ranking[s] = {
786                                id: s,
787                                score: total_solver_instance[s][i],
788                                color: "none"
789                            };
790                        } else {
791                            ranking[s] = {
792                                id: s,
793                                score: -1.0,
794                                color: "none"
795                            };
796                        }
797                    }
798
799                    // Generate the ranking and mapping
800                    rankAndMap(ranking, map);
801
802                    let bd = document.createElement('tbody');
803                    const row = document.createElement('tr');
804                    if (loc_problems[p] != 'null') {
805                        row.appendChild(createLinkCol(
806                            `${problems[p]} (${kind[p]})`, loc_problems[p]
807                        ));
808                    } else {
809                        row.appendChild(createTxtCol(
810                            `${problems[p]} (${kind[p]})`
811                        ));
812                    }
813                    row.appendChild(createLinkCol(benchmarks[i], loc_instances[i]));
814                    row.appendChild(createTxtCol("TOTAL", "left"));
815                    row.appendChild(createTxtCol(" ", "left"));
816                    row.appendChild(createTxtCol(" ", "left"));
817                    row.appendChild(createTxtCol(" ", "left"));
818                    row.appendChild(createTxtCol(total_instance[i].toFixed(0), "right"));
819                    if (hasIncompleteScoring) {
820                        row.appendChild(createTxtCol(total_instance_inc[i].toFixed(0), "right"));
821                    }
822                    if (hasAreaScoring) {
823                        row.appendChild(createTxtCol(total_instance_area[i].toFixed(3), "right"));
824                    }
825                    bd.appendChild(row);
826                    tbl.appendChild(bd);
827                    bd = document.createElement('tbody');
828                    let p_string = problems[p];
829                    let i_string = benchmarks[i];
830                    for (let s = 0; s < nb_s; s++) {
831                        if (selected_solver[s]) {
832                            const tr = [p_string, i_string, solvers[s],
833                                results[s][i], times[s][i], objectives[s][i],
834                                total_solver_instance[s][i].toFixed(2),
835                            ]
836                            if (hasIncompleteScoring) {
837                                tr.push(total_solver_instance_inc[s][i].toFixed(2));
838                            }
839                            if (hasAreaScoring) {
840                                tr.push(total_solver_instance_area[s][i].toFixed(2));
841                            }
842                            if (ranking[map[s]].color == "none" || ranking[map[s]].score <= 0.0) {
843                                addRowText(bd, tr, 4);
844                            } else {
845                                addRowTextWithColor(bd, tr, 4, ranking[map[s]].color, 2);
846                            }
847                            p_string = " ";
848                            i_string = " ";
849                        }
850                    }
851                    tbl.appendChild(bd);
852                }
853            }
854        }
855    }
856
857    function modifyInstancePlots(selected_solver, selected_problem, xaxis_type, lineshape) {
858        const tbl = document.getElementsByName('objective_plots')[0];
859        for (let p = 0; p < nb_p; p++) {
860            if (selected_problem[p]) {
861                for (let k = 0;
861 k < instances[p].length; k++) {
862                    const i = instances[p][k];
863                    let bd = document.createElement('tbody');
864                    let row = document.createElement('tr');
865                    if (loc_problems[p] != 'null') {
866                        row.appendChild(
867                            createLinkCol(`${problems[p]} (${kind[p]})`, loc_problems[p])
868                        );
869                    } else {
870                        row.appendChild(
871                            createTxtCol(`${problems[p]} (${kind[p]})`)
872                        );
873                    }
874                    row.appendChild(createLinkCol(benchmarks[i], loc_instances[i]));
875                    row.appendChild(createTxtCol("Plot", "left"));
876                    bd.appendChild(row);
877                    tbl.appendChild(bd);
878
879                    bd = document.createElement('tbody');
880
881                    row = document.createElement('tr');
882                    // First column
883                    let col = document.createElement('td');
884                    let txt = document.createTextNode(problems[p]);
885                    col.align = "left";
886                    col.appendChild(txt);
887                    row.appendChild(col);
888
889                    // Second column
890                    col = document.createElement('td');
891                    txt = document.createTextNode(benchmarks[i]);
892                    col.align = "left";
893                    col.appendChild(txt);
894                    row.appendChild(col);
895
896                    // Third column
897                    col = document.createElement('td');
898                    const div = document.createElement('div');
899                    div.id = p + benchmarks[i];
900                    col.appendChild(div);
901                    row.appendChild(col);
902
903                    bd.appendChild(row);
904
905                    tbl.appendChild(bd);
906                }
907            }
908        }
909        // Plotting
910        for (let p = 0; p < nb_p; p++) {
911            //Check if the problem was selected
912            if (!selected_problem[p])
913                continue;
914            // Problem is selected
915            for (let k = 0; k < instances[p].length; k++) {
916                const i = instances[p][k];
917                const data = getDataForObjectivePlot(selected_solver, p, i, lineshape);
918                const layout = {
919                    title: `${problems[p]}   ${benchmarks[i]}`,
920                    xaxis: {
921                        title: 'time in ms',
922                        type: xaxis_type
923                    },
924                    yaxis: {
925                        title: 'objective value'
926                    },
927                    showlegend: true,
928                    height: 700,
929                    legend: {
930                        orientation: 'h'
931                    }
932                };
933                //console.log(data);
934                Plotly.newPlot(p + benchmarks[i], data, layout);
935            }
936        }
937    }
938
939    function getDataForObjectivePlot(selected_s, p, i, lineshape) {
940        const data = [];
941        let index = 0;
942        let min_obj = 0;
943        let max_obj = 0;
944        let sol = false;
945        // Compute minimal and maximal objective
946        for (let s = 0; s < nb_s; s++) {
947            if (!selected_s[s])
948                continue;
949            if (step_count[s][i] > 0) {
950                if (sol) {
951                    min_obj = Math.min(min_obj, objectives[s][i]);
952                    max_obj = Math.max(max_obj, objectives[s][i]);
953                    min_obj = Math.min(min_obj, first_objectives[s][i]);
954                    max_obj = Math.max(max_obj, first_objectives[s][i]);
955                } else {
956                    sol = true;
957                    min_obj = Math.min(objectives[s][i], first_objectives[s][i]);
958                    max_obj = Math.max(objectives[s][i], first_objectives[s][i]);
959                }
960            }
961        }
962        // Generate data
963        if (sol) {
964            for (let s = 0; s < nb_s; s++) {
965                if (!selected_s[s])
966                    continue;
967                if (step_count[s][i] > 0) {
968                    let trace = {};
969                    if (lineshape == 'lines') {
970                        trace = {
971                            x: step_times[s][i],
972                            y: step_obj[s][i],
973                            type: 'scatter',
974                            name: solvers[s]
975                        };
976                    } else {
977                        trace = {
978                            x: step_times[s][i],
979                            y: step_obj[s][i],
980                            type: 'scatter',
981                            line: {
982                                shape: lineshape
983                            },
984                            name: solvers[s]
985                        };
986                    }
987                    data[index] = trace;
988                    index++;
989                }
990            }
991        }
992        return data;
993    }
994
995
996    function modifyTables(selected_solver, selected_problem) {
997        const tables = ["total_table", "problem_table", "instance_table", "objective_plots"];
998        for (const i in tables) {
999            const tbl_l = document.getElementsByName(tables[i]);
1000            const tbl = tbl_l[0];
1001            while (tbl.tBodies.length > 0)
1002                tbl.removeChild(tbl.tBodies[0]);
1003        }
1004        modifyToTal(selected_solver, selected_problem);
1005        modifyProblem(selected_solver, selected_problem);
1006        modifyInstance(selected_solver, selected_problem);
1007
1008        // Retrieve parameters for plotting
1009
1010        // x-axis type
1011        let xaxis_type = '-';
1012        if (document.getElementById("xaxis_linear").checked) {
1013            xaxis_type = 'linear';
1014        } else if (document.getElementById("xaxis_log").checked) {
1015            xaxis_type = 'log';
1016        }
1017        // lineshape type
1018        let lineshape = 'hv';
1019        if (document.getElementById("lineshape_lines").checked) {
1020            lineshape = 'lines';
1021        }
1022        // Draw plots for each instance
1023        if (document.getElementById("plot_instance").checked) {
1024            modifyInstancePlots(selected_solver, selected_problem, xaxis_type, lineshape);
1025            document.getElementById('plots-section').style.display = 'block';
1026        } else {
1027            document.getElementById('plots-section').style.display = 'none';
1028        }
1029        // Draw plot for the total score
1030        // XXX Disable it, because it is not finished yet
1031        //if (document.getElementById("plot_totalscore").checked) {
1032        //    draw_scores_over_time(selected_solver, selected_problem, xaxis_type, lineshape, timestep);
1033        //}
1034    }
1035
1036    function sortTotalTable(col, sort_criteria) {
1037        console.log(`column: ${col}`);
1038        sortTable("total_table", col, 2, sort_criteria);
1039    }
1040
1041    // Adapted from https://www.w3schools.com/howto/howto_js_sort_table.asp
1042    function sortTable(name, col, col_start, sort_criteria) {
1043        let table, rows, switching, i, x, y, shouldSwitch, dir, switchcount = 0;
1044        table = document.getElementById(name);
1045        switching = true;
1046        // Set the sorting direction to ascending:
1047        dir = "asc";
1048        console.log(table);
1049        // Make a loop that will continue until no switching has been done:
1050        while (switching) {
1051            //start by saying: no switching is done:
1052            switching = false;
1053            rows = table.getElementsByTagName("tr");
1054            /*Loop through all table rows (except the
1055            first, which contains table headers):*/
1056            for (i = col_start; i < (rows.length - 1); i++) {
1057                //start by saying there should be no switching:
1058                shouldSwitch = false;
1059                /*Get the two elements you want to compare,
1060                one from current row and one from the next:*/
1061                x = rows[i].getElementsByTagName("td")[col];
1062                y = rows[i + 1].getElementsByTagName("td")[col];
1063                /*check if the two rows should switch place,
1064                based on the direction, asc or desc:*/
1065                if (dir == "asc") {
1066                    if (
1067                        (sort_criteria == "string" && x.innerHTML.toLowerCase() > y.innerHTML.toLowerCase()) ||
1068                        (sort_criteria == "number" && parseFloat(x.innerHTML) > parseFloat(y.innerHTML))
1069                    ) {
1070                        //if so, mark as a switch and break the loop:
1071                        shouldSwitch = true;
1072                        break;
1073                    }
1074                } else if (dir == "desc") {
1075                    if (
1076                        (sort_criteria == "string" && x.innerHTML.toLowerCase() < y.innerHTML.toLowerCase()) ||
1077                        (sort_criteria == "number" && parseFloat(x.innerHTML) < parseFloat(y.innerHTML))
1078                    ) {
1079                        //if so, mark as a switch and break the loop:
1080                        shouldSwitch = true;
1081                        break;
1082                    }
1083                }
1084            }
1085            if (shouldSwitch) {
1086                /*If a switch has been marked, make the switch
1087                and mark that a switch has been done:*/
1088                rows[i].parentNode.insertBefore(rows[i + 1], rows[i]);
1089                switching = true;
1090                //Each time a switch is done, increase this count by 1:
1091                switchcount++;
1092            } else {
1093                /*If no switching has been done AND the direction is "asc",
1094                set the direction to "desc" and run the while loop again.*/
1095                if (switchcount == 0 && dir == "asc") {
1096                    dir = "desc";
1097                    switching = true;
1098                }
1099            }
1100        }
1101    }
1102
1103    function downloadResults() {
1104        const prob = [];
1105        const solv = [];
1106        for (let i = 0; i < nb_p; i++) {
1107            prob[i] = pbox[i].checked;
1108        }
1109        for (let i = 0; i < nb_s; i++) {
1110            solv[i] = sbox[i].checked;
1111        }
1112        computeScores(solv, prob);
1113        if (hasIncompleteScoring) {
1114            computeScoresInc(solv, prob);
1115        }
1116        if (hasAreaScoring) {
1117            computeScoresArea(solv, prob);
1118        }
1119        const headings = ["Problem", "Kind", "Instance", "Solver", "Status", "Time", "Objective", "Score"];
1120        if (hasIncompleteScoring) {
1121            headings.push("Score Incomplete");
1122        }
1123        if (hasAreaScoring) {
1124            headings.push("Score Area");
1125        }
1126        const csv = [headings];
1127        for (let p = 0; p < nb_p; p++) {
1128            if (prob[p]) {
1129                for (let k = 0; k < instances[p].length; k++) {
1130                    const i = instances[p][k];
1131                    const p_string = problems[p];
1132                    const k_string = kind[p];
1133                    const i_string = benchmarks[i];
1134                    for (let s = 0; s < nb_s; s++) {
1135                        if (solv[s]) {
1136                            const row = [p_string, k_string, i_string, solvers[s],
1137                                results[s][i], times[s][i], objectives[s][i],
1138                                total_solver_instance[s][i],
1139                            ]
1140                            if (hasIncompleteScoring) {
1141                                row.push(total_solver_instance_inc[s][i]);
1142                            }
1143                            if (hasAreaScoring) {
1144                                row.push(total_solver_instance_area[s][i]);
1145                            }
1146                            csv.push(row);
1147                        }
1148                    }
1149                }
1150            }
1151        }
1152        // Export as CSV
1153        let csvContent = "data:text/csv;charset=utf-8,";
1154        csv.forEach(function (rowArray) {
1155            let row = rowArray.join(",");
1156            csvContent += row + "\r\n";
1157        });
1158        const encodedUri = encodeURI(csvContent);
1159        const link = document.createElement("a");
1160        link.setAttribute("href", encodedUri);
1161        link.setAttribute("download", "results.csv");
1162        document.body.appendChild(link);
1163        link.click();
1164    }
1165
1166    function downloadSteps() {
1167        if (!hasAreaScoring) {
1168            return;
1169        }
1170        const prob = [];
1171        const solv = [];
1172        for (let i = 0; i < nb_p; i++) {
1173            prob[i] = pbox[i].checked;
1174        }
1175        for (let i = 0; i < nb_s; i++) {
1176            solv[i] = sbox[i].checked;
1177        }
1178        const headings = ["Problem", "Instance", "Solver", "Time", "Objective"];
1179        const csv = [headings];
1180        for (let p = 0; p < nb_p; p++) {
1181            if (prob[p]) {
1182                for (let k = 0;
1182 k < instances[p].length; k++) {
1183                    const i = instances[p][k];
1184                    const p_string = problems[p];
1185                    const i_string = benchmarks[i];
1186                    for (let s = 0; s < nb_s; s++) {
1187                        if (solv[s]) {
1188                            for (let j = 0; j < step_count[s][i]; j++) {
1189                                const row = [p_string, i_string, solvers[s], step_times[s][i][j]];
1190                                const obj = step_obj[s][i][j];
1191                                row.push(obj === ' ' ? '' : obj);
1192                                csv.push(row);
1193                            }
1194                        }
1195                    }
1196                }
1197            }
1198        }
1199        // Export as CSV
1200        let csvContent = "data:text/csv;charset=utf-8,";
1201        csv.forEach(function (rowArray) {
1202            let row = rowArray.join(",");
1203            csvContent += row + "\r\n";
1204        });
1205        const encodedUri = encodeURI(csvContent);
1206        const link = document.createElement("a");
1207        link.setAttribute("href", encodedUri);
1208        link.setAttribute("download", "objectives.csv");
1209        document.body.appendChild(link);
1210        link.click();
1211    }
1212    
1213    init();
1214
1215    return {
1216        selectFD,
1217        selectFree,
1218        selectPar,
1219        selectOpen,
1220        selectLocal,
1221        selectAll,
1222        clearAll,
1223        computeSelected,
1224        sortTotalTable,
1225        downloadResults,
1226        downloadSteps
1227    }
1228}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.