Skip to content

Add/cobi 153#168

Open
CIGbalance wants to merge 10 commits intopush-zmvqzzrwnlupfrom
add/cobi_153
Open

Add/cobi 153#168
CIGbalance wants to merge 10 commits intopush-zmvqzzrwnlupfrom
add/cobi_153

Conversation

@CIGbalance
Copy link
Copy Markdown
Collaborator

Testing the new schema based on COBI problem generator. Main issues I encountered:

  • Took me a second to figure out that the Generator is ProblemLike, so I didn't need to define separate problems
  • I don't know if there is a maximum number of variables
  • I assume box constraints are per variable, but that is dynamic
  • I can add an arbitrary amount of linear / function-based constraints (only specific functions)
  • For the strings, I might have put different values than others
  • I didn't know how to put the code example (and it is not finished)

Fix I did: I was not able to serialise the references when they were a set.

Closes #153

Output:

cobi_impl:
  description: Python library for COBI (COnstrained BI-objective optimization) 
    problem generator
  evaluation_time: null
  language: python
  links:
  - type: repository
    url: https://github.com/numbbo/cobi-problem-generator/
  - type: v0.5.0
    url: https://github.com/numbbo/cobi-problem-generator/releases/tag/v0.5.0
  name: COBI Implementation
  requirements: 
    https://github.com/numbbo/cobi-problem-generator/blob/main/requirements.txt
  type: implementation
cobi_problem:
  allows_partial_evaluation: no
  can_evaluate_objectives_independently: no
  code_examples:
  - ./code_153.py
  constraints:
    box: 1
    function: 100
    linear: 100
  description: Generator of COnstrained BI-objective optimization problems
  dynamic_type: null
  fidelity_levels:
  - 1
  implementations:
  - cobi_impl
  long_name: null
  modality:
  - multi-modal per objective
  name: COBI Problem
  noise_type:
  - none
  objectives:
  - 2
  references:
  - authors:
    - Anne Auger
    - Dimo Brockhoff
    - Luka Opravˇs
    - Tea Tuˇsar
    link:
      type: arxiv
      url: https://arxiv.org/abs/2604.09131
    title: Pareto Set Characterization in Constrained Multiobjective 
      Optimization and the COBI Problem Generator
  soft_constraints: null
  source:
  - artificial
  tags:
  - bi-objective
  - continuous
  - multi-peak
  - convex-quadratic
  - constrained
  - location
  - black-box
  type: generator
  variables:
    binary: 0
    categorical: 0
    continuous:
      max: 100
      min: 1
    integer: 0

Dvermetten and others added 4 commits April 21, 2026 16:15
* adding merge script (untested)

* making tests not fail

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Change example problem format to YAML

Updated example problem format from JSON to YAML.

* requested changes

* follow new workflow

* tested script now

* remove from PR

* remove unnecessary changes here

* undoing changes

* removing additional changes

* undoing changes

* remove file again

* finishing merge

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* new_data None

* imports

* removing no changes

* add typing

* change to manual mode

* updated for new workflow

* Apply suggestions from code review

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* some additional review updates

* check format fixes

* do not write if failing

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings April 21, 2026 15:50
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds COBI generator metadata/example while improving the docs table UI and extending YAML tooling to support validating/merging problem entries.

Changes:

  • Update schema to serialize references properly (set → list) and add a COBI example YAML generator script.
  • Enhance the generated docs table with a column-visibility toolbar and a “problem details” panel (new HTML template + updated JS/CSS).
  • Refactor YAML validation to expose validate_data() and introduce a new utils/merge_yaml.py workflow documented in utils/README.md.

Reviewed changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
yaml_to_html.py Injects a reusable table template and generates column toggle UI.
utils/validate_yaml.py Adds typing and extracts validate_data() for reuse by other tooling.
utils/merge_yaml.py New script to merge a separate YAML file into problems.yaml.
utils/README.md Documents updated workflow and new merge script.
src/opltools/schema.py Fixes references serialization by changing it to a list; formatting cleanups.
examples/p_153.py Adds a COBI generator/library example producing YAML via pydantic_yaml.
examples/code_153.py Adds a minimal COBI usage snippet.
docs/table_template.html New template for table toolbar + details panel wrapper.
docs/table_styles.css Overhauls styling to support toolbar + details panel.
docs/problems.html Updates the rendered table markup to include toolbar + details section.
docs/javascript.html Adds column toggles, row-selection details rendering, and other UI behavior.
docs/index.html Updates the generated main page to include the new table shell + details UI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread utils/merge_yaml.py
Comment on lines +72 to +75
# Validate resulting data
final_status, final_data = validate_yaml(big_yaml_path)
if final_status != 0 or final_data is None:
print(
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

validate_yaml() now exits the process and returns None, but this script calls it expecting (status, data). This will raise (or terminate via SystemExit) and makes merge_yaml.py unusable. Use read_data() + validate_data() for the final validation (or refactor validate_yaml() to return a boolean/status instead of calling sys.exit).

Copilot uses AI. Check for mistakes.
Comment thread utils/merge_yaml.py
Comment on lines +80 to +81
print(
f"::notice::Merged {len(new_data)} new problems into {big_yaml_path}. {new_problems_yaml_path} can now be deleted."
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The script claims the new-problems YAML “can now be deleted”, but it never deletes it. Either remove this message (and the README claim) or actually delete the file after a successful merge (e.g., Path(new_problems_yaml_path).unlink()).

Suggested change
print(
f"::notice::Merged {len(new_data)} new problems into {big_yaml_path}. {new_problems_yaml_path} can now be deleted."
try:
Path(new_problems_yaml_path).unlink()
except OSError as e:
print(
f"::error::Merged data into {big_yaml_path}, but failed to delete {new_problems_yaml_path}: {e}"
)
return False
print(
f"::notice::Merged {len(new_data)} new problems into {big_yaml_path} and deleted {new_problems_yaml_path}."

Copilot uses AI. Check for mistakes.
Comment thread utils/validate_yaml.py
Comment on lines 34 to 38
num_problems = len(data)
if not isinstance(data, list):
print("::error::YAML file should contain a list of entries.")
return False
if len(data) < 1:
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

check_format() calls len(data) before verifying data is a list. If the YAML top-level is a scalar (e.g. an int), this will raise TypeError instead of producing a validation error. Check isinstance(data, list) (and handle None) before calling len().

Suggested change
num_problems = len(data)
if not isinstance(data, list):
print("::error::YAML file should contain a list of entries.")
return False
if len(data) < 1:
if data is None:
print("::error::YAML file should contain a list of entries.")
return False
if not isinstance(data, list):
print("::error::YAML file should contain a list of entries.")
return False
num_problems = len(data)
if num_problems < 1:

Copilot uses AI. Check for mistakes.
Comment thread utils/README.md

## merge_yaml.py

This script merges a new problem description in a separate yaml file into the main [problems.yaml](../problems.yaml) file. It runs the validation checks from the above script before merging and deletes the separate yaml file after merging.
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This says the merge script “deletes the separate yaml file after merging”, but utils/merge_yaml.py currently does not delete it. Please either implement deletion (and mention it’s irreversible) or adjust this description to match actual behavior.

Suggested change
This script merges a new problem description in a separate yaml file into the main [problems.yaml](../problems.yaml) file. It runs the validation checks from the above script before merging and deletes the separate yaml file after merging.
This script merges a new problem description in a separate yaml file into the main [problems.yaml](../problems.yaml) file. It runs the validation checks from the above script before merging.

Copilot uses AI. Check for mistakes.
Comment thread docs/javascript.html
Comment on lines +70 to +83
const detailsHtml = headers
.map((label, index) => {
const value = rowData[index] || '<span class="details-empty">n/a</span>';
return `<div class="detail-item"><dt>${escapeHtml(label)}</dt><dd>${value}</dd></div>`;
})
.join('');

const name = stripHtml(rowData[0]);
if (detailsHint) {
detailsHint.textContent = name ? `Selected: ${name}` : 'Selected row';
}

detailsContent.innerHTML = detailsHtml;
};
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

renderRowDetails() builds HTML using rowData[index] and then assigns it via innerHTML. Because table cell content ultimately comes from YAML and yaml_to_html.py renders cells with escape=False, this enables XSS if any YAML string contains HTML/script. Consider sanitizing values before injecting (e.g., escape everything and only allow safe link markup, or use a sanitizer like DOMPurify).

Copilot uses AI. Check for mistakes.
Comment thread docs/table_template.html
<section class="details-shell" id="problem-details" aria-live="polite">
<h3 class="details-title">Problem details</h3>
<p class="details-hint" id="problem-details-hint">Click a table row to inspect full details.</p>
<dl class="details-grid" id="problem-details-content"></dl>
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The details container is a <dl>, but the JS renders each item wrapped in a <div> containing <dt>/<dd>. In HTML, <dt>/<dd> should be direct children of <dl> for correct semantics/screen reader navigation. Either change the container to a regular <div> (and use appropriate roles) or render dt/dd pairs directly without a wrapper element.

Suggested change
<dl class="details-grid" id="problem-details-content"></dl>
<div class="details-grid" id="problem-details-content"></div>

Copilot uses AI. Check for mistakes.
Comment thread examples/p_153.py
Comment on lines +47 to +49
box=ValueRange(min=0, max=None),
linear=ValueRange(min=0, max=None),
function=ValueRange(min=0, max=None),
Copy link

Copilot AI Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example constructs ValueRange(min=0, max=None) for constraints. With the current ValueRange validator (if not min and not max), min=0 is treated as empty and raises a validation error, so this example won’t run as written. Either update ValueRange to treat 0 as valid (check is None instead of falsiness) or avoid min=0 in the example.

Suggested change
box=ValueRange(min=0, max=None),
linear=ValueRange(min=0, max=None),
function=ValueRange(min=0, max=None),
box=ValueRange(min=1, max=None),
linear=ValueRange(min=1, max=None),
function=ValueRange(min=1, max=None),

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants