Skip to content

ROSE Spec for Service#97

Open
AymenFJA wants to merge 10 commits into
mainfrom
feature/yaml-spec
Open

ROSE Spec for Service#97
AymenFJA wants to merge 10 commits into
mainfrom
feature/yaml-spec

Conversation

@AymenFJA

Copy link
Copy Markdown
Collaborator

Creating a YAML spec approach for better defining and re-using pre-defined learner recipes in ROSE. Mainly for service users.

@AymenFJA AymenFJA self-assigned this Jun 18, 2026
@AymenFJA AymenFJA added raas ROSE As A Service Q2 labels Jun 18, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a YAML Spec API layer to ROSE, allowing users to define Active Learning, Reinforcement Learning, and UQ workflows declaratively. It adds Pydantic-based schema validation, task adapters for Python and shell execution, a builder to construct learners, and comprehensive unit and integration tests. Additionally, the documentation has been updated with new guides, Mermaid diagrams, and a deprecation warning for RadicalExecutionBackend. Review feedback identifies a bug in build_learner_configs where parameters are discarded for parallel learners when cfg.learners is None, a typo in docs/index.md, and a recommendation to use standard dictionary equality instead of string-serialized sorted items for robust task description comparison in rose/spec/schema.py.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread rose/spec/builder.py
Comment on lines +103 to +129
def build_learner_configs(self):
"""LearnerConfig list for parallel learners, or None if no learners defined."""
cfg = self.config
if cfg.learners is None:
return None
from rose.learner import LearnerConfig, TaskConfig

required = _REQUIRED_SLOTS[cfg.learner.type]
configs = []
max_iter = cfg.learner.max_iter
params = dict(cfg.parameters)
params["pythonpath"] = list(cfg.remote.pythonpath)
lc_slots = required & _LEARNER_CONFIG_SLOTS
for i, learner_def in enumerate(cfg.learners):
# learner_id → dispatch routing key (popped by closure, never reaches user fn)
# iteration → per-entry so get_task_config(slot, n) returns the right value
# learner_label → human-readable learner name; only injected when non-empty
# parameters → user-defined values from the YAML parameters: block
base = {"learner_id": i, **params}
if learner_def.label:
base["learner_label"] = learner_def.label
schedule = {n: TaskConfig(kwargs={**base, "iteration": n}) for n in range(max_iter + 1)}
schedule[-1] = TaskConfig(kwargs={**base, "iteration": max_iter})
configs.append(
LearnerConfig(**{slot: schedule for slot in lc_slots}, criterion=schedule)
)
return configs

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

When cfg.learners is None (meaning shared tasks are used for parallel learners), build_learner_configs currently returns None. This means that any parameters defined in the parameters: block of the YAML spec are completely discarded and never passed to the parallel learners. We should generate the LearnerConfig list even when cfg.learners is None if parameters or remote pythonpath are defined.

    def build_learner_configs(self):
        """LearnerConfig list for parallel learners, or None if no learners or parameters defined."""
        cfg = self.config
        if cfg.learners is None and not cfg.parameters and not cfg.remote.pythonpath:
            return None
        from rose.learner import LearnerConfig, TaskConfig

        required = _REQUIRED_SLOTS[cfg.learner.type]
        configs  = []
        max_iter = cfg.learner.max_iter
        params   = dict(cfg.parameters)
        params["pythonpath"] = list(cfg.remote.pythonpath)
        lc_slots = required & _LEARNER_CONFIG_SLOTS
        num_learners = len(cfg.learners) if cfg.learners is not None else cfg.learner.parallel_learners
        for i in range(num_learners):
            # learner_id    → dispatch routing key (popped by closure, never reaches user fn)
            # iteration     → per-entry so get_task_config(slot, n) returns the right value
            # learner_label → human-readable learner name; only injected when non-empty
            # parameters    → user-defined values from the YAML parameters: block
            base = {"learner_id": i, **params}
            if cfg.learners is not None and cfg.learners[i].label:
                base["learner_label"] = cfg.learners[i].label
            schedule = {n: TaskConfig(kwargs={**base, "iteration": n}) for n in range(max_iter + 1)}
            schedule[-1] = TaskConfig(kwargs={**base, "iteration": max_iter})
            configs.append(
                LearnerConfig(**{slot: schedule for slot in lc_slots}, criterion=schedule)
            )
        return configs

Comment thread docs/index.md Outdated
## What is ROSE? 🌹

ROSE: RADICAL Orchestrator for Surrogate Exploration (ROSE) toolkit is a framework designed to enable the concurrent and adaptive execution of simulation, surrogate training, and selection tasks on High-Performance Computing (HPC) resources. ROSE is a Python package that provides tools for developing active and reinforcement learning (AL and RL) methods for scientific applications. It enables users to define simulation and surrogate training tasks and automatically manage their execution on HPC resources via a predefined set of Learning Policies (Learners).
ROSE: RADICAL Orchestrator for Surrogate Exploration (ROSE) toolkit is a framework designed to enable the distribuited, concurrent and adaptive execution of simulation, surrogate training, and selection tasks on High-Performance Computing (HPC) resources at a scale. ROSE is a Python package that provides tools for developing active and reinforcement learning (AL and RL) methods for scientific applications. It enables users to define simulation and surrogate training tasks and automatically manage their execution on HPC resources via a predefined set of Learning Policies (Learners).

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

There is a typo in this line: 'distribuited' should be 'distributed'.

Suggested change
ROSE: RADICAL Orchestrator for Surrogate Exploration (ROSE) toolkit is a framework designed to enable the distribuited, concurrent and adaptive execution of simulation, surrogate training, and selection tasks on High-Performance Computing (HPC) resources at a scale. ROSE is a Python package that provides tools for developing active and reinforcement learning (AL and RL) methods for scientific applications. It enables users to define simulation and surrogate training tasks and automatically manage their execution on HPC resources via a predefined set of Learning Policies (Learners).
ROSE: RADICAL Orchestrator for Surrogate Exploration (ROSE) toolkit is a framework designed to enable the distributed, concurrent and adaptive execution of simulation, surrogate training, and selection tasks on High-Performance Computing (HPC) resources at a scale. ROSE is a Python package that provides tools for developing active and reinforcement learning (AL and RL) methods for scientific applications. It enables users to define simulation and surrogate training tasks and automatically manage their execution on HPC resources via a predefined set of Learning Policies (Learners).

Comment thread rose/spec/schema.py Outdated
"All learners must use the same type for a given slot."
)
descs = [dict(l.tasks[slot].task_description or {}) for l in self.learners]
if len({str(sorted(d.items())) for d in descs}) > 1:

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

Using str(sorted(d.items())) to compare dictionaries can cause false validation failures if the dictionaries contain nested dictionaries with different key insertion orders (since dictionary insertion order is preserved in Python 3.7+). Using standard dictionary equality == is more robust and handles nested structures correctly regardless of key ordering.

Suggested change
if len({str(sorted(d.items())) for d in descs}) > 1:
if descs and any(d != descs[0] for d in descs):

AymenFJA added 5 commits June 18, 2026 23:33
1-Improve docs
2-Remove RadicalExecutionBackend from docs
3-Address Gemini comments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Q2 raas ROSE As A Service

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant