Skip to content

Implementation of the Predictor Tracer#641

Merged
flowerthrower merged 32 commits into
munich-quantum-toolkit:qce-experimentsfrom
linus-hologram:thesis-predictor-visualization
Apr 21, 2026
Merged

Implementation of the Predictor Tracer#641
flowerthrower merged 32 commits into
munich-quantum-toolkit:qce-experimentsfrom
linus-hologram:thesis-predictor-visualization

Conversation

@linus-hologram
Copy link
Copy Markdown

@linus-hologram linus-hologram commented Apr 12, 2026

Description

This PR implements the Predictor Tracer backend which collects information about the RL compilation process of the MQT Predictor. If active, the tracer outputs the collected information to a json file, which will later be used in the Predictor Tracer frontend do visualize the compilation.

AI Usage

The idea, logical structure and functionality of the code are entirely my own work; Google Gemini Pro 3.1 was solely used to assist with writing valid Python code. All code that was produced by Gemini was carefully reviewed and tested by myself.

Checklist

  • The pull request only contains commits that are focused and relevant to this change.
  • I have added appropriate tests that cover the new/changed functionality.
  • I have updated the documentation to reflect these changes.
  • I have added entries to the changelog for any noteworthy additions, changes, fixes, or removals.
  • I have added migration instructions to the upgrade guide (if needed).
  • The changes follow the project's style guidelines and introduce no new warnings.
  • The changes are fully tested and pass the CI checks.
  • I have reviewed my own code changes.

If PR contains AI-assisted content:

  • I have disclosed the use of AI tools in the PR description as per our AI Usage Guidelines.
  • I confirm that I have personally reviewed and understood all AI-generated content, and accept full responsibility for it.

linus-hologram and others added 18 commits April 1, 2026 19:24
- renamed CompilationVisualizer to CompilationTracer
- included first draft of actual tracing logic inside predictorenv.py
- adjusted qcompile.py and predictor.py accordingly to route through the tracer_output_path
The DeviceMetadata class now also includes the device's native gates, its topology and gate calibration data.
- each compilation step is now associated with its figure of merit value and its kind (exact vs. approximate)
…on steps

- gate count does now not include barriers
- program_communication, critical_depth, entanglement_ratio, parallelism, liveness are now also captured for each compilation step
- initial circuit is now captured as first value in the steps array (step_index 0), removed InputCircuitMetadata class from tracer.py
- predictorenv.py was adjusted to calculate the initial figure_of_merit value already in the reset() method, stripping away the None-check inside the step method (step() can only ever be called after reset() was called on the environment, thereby the prev_reward and prev_reward_kind always have to be set)
- changed data type for prev_reward and prev_reward_kind to float and str, respectively, and provided initial values.
The tracer now tracks the MDP policy as well as the MDP state evolution throughout the compilation.
This happens regardless of what the actual figure of merit is
… into thesis-predictor-visualization

# Conflicts:
#	src/mqt/predictor/rl/predictor.py
#	src/mqt/predictor/rl/predictorenv.py
@linus-hologram
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Compilation tracing: detailed per-step compilation logs exported to JSON.
    • New option to specify a tracer output path to save trace data (circuit metrics, steps, figures of merit).
  • Tests

    • Added an automated test validating generated tracer JSON structure and contents.
  • Chores

    • Removed unused/obsolete imports and dependencies.

Walkthrough

Adds a CompilationTracer that records device metadata and per-step RL compilation snapshots (metrics, features, flags) and exports the collected episode trace to a JSON file when an episode completes; exposes tracer output path through public qcompile/rl_compile/Predictor APIs and includes a test and changelog entry.

Changes

Cohort / File(s) Summary
Public API
src/mqt/predictor/qcompile.py
Added optional tracer_output_path parameter to qcompile and forwarded it to rl_compile.
RL entrypoints
src/mqt/predictor/rl/predictor.py
Added tracer_output_path to Predictor.__init__ and rl_compile; constructs Predictor with tracer when no singleton, or temporarily overrides/restores predictor.env.tracer_output_path when reusing a singleton.
RL environment
src/mqt/predictor/rl/predictorenv.py
Added tracer_output_path field; introduced self.tracer and per-step tracer collection via _collect_tracer_data; refactored reward calculation into public helpers and ensured tracer baseline/init on reset; saves JSON on episode completion.
Tracer implementation
src/mqt/predictor/rl/tracer.py
New module: dataclasses for device/step/FOM metadata and CompilationTracer with from_initial_state, record_step, and save_to_json to assemble and persist JSON traces.
Cleanup
src/mqt/predictor/rl/actions.py
Removed unused os and BQSKit-related imports; cosmetic comment formatting changes.
Changelog & tests
CHANGELOG.md, tests/compilation/test_tracer.py
Changelog entry added for CompilationTracer; new test test_compilation_tracer_generates_valid_json runs rl_compile(..., tracer_output_path=...), asserts trace JSON exists, validates schema/top-level keys and dataclass-compatibility for device and steps.

Sequence Diagram

sequenceDiagram
    participant User as User
    participant QCompile as qcompile
    participant RLCompile as rl_compile
    participant Predictor as Predictor
    participant Env as PredictorEnv
    participant Tracer as CompilationTracer
    participant FS as FileSystem

    User->>QCompile: qcompile(..., tracer_output_path)
    QCompile->>RLCompile: rl_compile(..., tracer_output_path)
    RLCompile->>Predictor: new or existing Predictor(tracer_output_path)
    Predictor->>Env: PredictorEnv(tracer_output_path)
    Env->>Tracer: CompilationTracer.from_initial_state(device, circuit, fom, policy)

    loop compilation steps
        RLCompile->>Env: step(action)
        Env->>Tracer: record_step(index, action, reward, current_qc, fom, features, flags)
    end

    Env->>Tracer: save_to_json() [on done]
    Tracer->>FS: write JSON trace
    FS-->>User: trace file persisted
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

feature

Suggested reviewers

  • burgholzer

🐇 I hopped through circuits, gate by gate,
I logged each depth and every state,
With JSON crumbs I traced the run,
Saved every step when the episode was done,
A little hop, a compiled sun.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Implementation of the Predictor Tracer' directly and clearly summarizes the main change: adding a tracer backend to collect and export compilation process information.
Description check ✅ Passed The description includes purpose, methodology, AI disclosure per guidelines, and completes most checklist items. However, documentation updates and CI passing verification remain unchecked.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/mqt/predictor/rl/actions.py (1)

365-379: 🧹 Nitpick | 🔵 Trivial

Remove dormant BQSKit blocks instead of retaining large commented code.

These blocks are effectively dead code and now reference removed dependencies/imports, which makes future reactivation error-prone. Prefer deleting them and keeping a brief note (or issue link) that BQSKit actions are intentionally disabled.

Also applies to: 525-547, 560-577

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/mqt/predictor/rl/actions.py` around lines 365 - 379, Remove the dormant,
commented BQSKit action blocks (the commented
register_action/DeviceDependentAction entries referencing "BQSKitO2" and the
bqskit_compile lambda) rather than keeping large commented code; delete those
commented sections wherever they appear and replace each with a concise
single-line note (or an issue/PR link) stating that BQSKit actions are
intentionally disabled and why, so reactivation won't reference removed imports
or cause confusion; ensure no other code references the symbols register_action,
DeviceDependentAction, or bqskit_compile remain expecting those commented
blocks.
src/mqt/predictor/rl/predictor.py (1)

43-54: 🧹 Nitpick | 🔵 Trivial

Add docstring documentation for tracer_output_path parameter.

The Predictor.__init__ docstring (line 45: "Initializes the Predictor object.") doesn't document the new tracer_output_path parameter. Per coding guidelines, Google-style docstrings should document all parameters.

Proposed docstring update
     def __init__(
         self,
         figure_of_merit: figure_of_merit,
         device: Target,
         mdp: str = "paper",
         path_training_circuits: Path | None = None,
         logger_level: int = logging.INFO,
         tracer_output_path: str | Path | None = None,
     ) -> None:
-        """Initializes the Predictor object."""
+        """Initializes the Predictor object.
+
+        Args:
+            figure_of_merit: The figure of merit to be used for compilation.
+            device: The target device to compile to.
+            mdp: The MDP transition policy. Defaults to "paper".
+            path_training_circuits: Path to training circuits folder. Defaults to None.
+            logger_level: Logging level. Defaults to logging.INFO.
+            tracer_output_path: If provided, enables compiler tracing and exports the JSON log to this path.
+        """

As per coding guidelines: "MUST use Google-style docstrings in Python code"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/mqt/predictor/rl/predictor.py` around lines 43 - 54, The
Predictor.__init__ docstring is missing documentation for the new
tracer_output_path parameter; update the Google-style docstring for
Predictor.__init__ to add a "Args:" entry describing tracer_output_path (type:
str | Path | None, purpose: path to write tracer output or None to disable
tracing) alongside the existing parameters, and ensure the wording matches the
style used for the other args and mentions default behavior; no functional code
changes required, just extend the docstring near the __init__ signature and keep
consistent formatting with other Google-style docstrings in the file.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CHANGELOG.md`:
- Line 17: The changelog entry for "CompilationTracer" contains a typo ("exports
collects" → "collects") and is missing the required PR number reference; update
the entry text for CompilationTracer to read "...collects compilation
information and exports it to a JSON file" and append the PR reference in the
changelog's link references (add [`#641`]:
https://github.com/munich-quantum-toolkit/predictor/pull/641) so the entry
follows the project's template and includes the PR number.

In `@src/mqt/predictor/rl/predictor.py`:
- Around line 208-210: The code mutates
predictor_singleton.env.tracer_output_path which can leak across invocations;
instead, capture the original value, set predictor.env.tracer_output_path to the
requested tracer_output_path, invoke the compilation/reset logic (e.g. call
reset() / rl_compile on predictor), and then restore the original
tracer_output_path in a finally block so the singleton state is always reverted
(or explicitly set back to None) even on exceptions; reference
predictor_singleton, predictor.env.tracer_output_path, rl_compile, and reset()
to locate the change.

In `@src/mqt/predictor/rl/tracer.py`:
- Line 19: The import in tracer.py uses "import qiskit.qasm2 as qasm2"; update
it to the explicit module import recommended by Ruff PLR0402 by changing it to
"from qiskit import qasm2" so usages of qasm2 in this file (e.g., any calls to
qasm2.loads or qasm2.parse) keep working with the preferred import style.
- Line 224: The tracer currently calls qasm2.dumps(current_qc) directly which
can raise and abort tracing; add a static helper like _safe_qasm_dumps(qc:
QuantumCircuit) that wraps qasm2.dumps in a try/except and returns a readable
fallback string (e.g. "// QASM2 export failed: {e}") on exception, then replace
the direct call in the trace construction (where
circuit_qasm=qasm2.dumps(current_qc)) with a call to
_safe_qasm_dumps(current_qc) so failures are captured but tracing continues.

In `@tests/compilation/test_tracer.py`:
- Around line 44-46: The test currently only asserts the first compilation step
is "Baseline"; update the assertions in tests/compilation/test_tracer.py to
cover multi-step scenarios by asserting len(trace_data["steps"]) > 1 and
verifying that the final or at least one subsequent step has is_terminal == True
(e.g., assert trace_data["steps"][-1]["is_terminal"] is True or assert
any(s.get("is_terminal") for s in trace_data["steps"])). Keep the existing
checks (first action and schema_version) and add these new assertions to ensure
later steps are recorded.
- Around line 34-35: The code redundantly wraps the already-Path object
trace_file with Path(trace_file) before opening; update the call in
tests/compilation/test_tracer.py to use trace_file.open(encoding="utf-8") (or
read_text() then json.loads) instead of Path(trace_file).open(...) so the
redundant Path() wrapper is removed and the file is opened directly from the
existing trace_file Path object.

---

Outside diff comments:
In `@src/mqt/predictor/rl/actions.py`:
- Around line 365-379: Remove the dormant, commented BQSKit action blocks (the
commented register_action/DeviceDependentAction entries referencing "BQSKitO2"
and the bqskit_compile lambda) rather than keeping large commented code; delete
those commented sections wherever they appear and replace each with a concise
single-line note (or an issue/PR link) stating that BQSKit actions are
intentionally disabled and why, so reactivation won't reference removed imports
or cause confusion; ensure no other code references the symbols register_action,
DeviceDependentAction, or bqskit_compile remain expecting those commented
blocks.

In `@src/mqt/predictor/rl/predictor.py`:
- Around line 43-54: The Predictor.__init__ docstring is missing documentation
for the new tracer_output_path parameter; update the Google-style docstring for
Predictor.__init__ to add a "Args:" entry describing tracer_output_path (type:
str | Path | None, purpose: path to write tracer output or None to disable
tracing) alongside the existing parameters, and ensure the wording matches the
style used for the other args and mentions default behavior; no functional code
changes required, just extend the docstring near the __init__ signature and keep
consistent formatting with other Google-style docstrings in the file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 8286a1a2-ca5b-4582-9e57-4bc320f4f5e8

📥 Commits

Reviewing files that changed from the base of the PR and between 0f8c197 and 6f2784a.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • src/mqt/predictor/qcompile.py
  • src/mqt/predictor/rl/actions.py
  • src/mqt/predictor/rl/predictor.py
  • src/mqt/predictor/rl/predictorenv.py
  • src/mqt/predictor/rl/tracer.py
  • tests/compilation/test_tracer.py

Comment thread CHANGELOG.md Outdated
Comment thread src/mqt/predictor/rl/predictor.py Outdated
Comment thread src/mqt/predictor/rl/tracer.py Outdated
Comment thread src/mqt/predictor/rl/tracer.py Outdated
Comment thread tests/compilation/test_tracer.py Outdated
Comment thread tests/compilation/test_tracer.py Outdated
linus-hologram and others added 2 commits April 13, 2026 19:16
wording fix

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Signed-off-by: Linus <42340116+linus-hologram@users.noreply.github.com>
@linus-hologram
Copy link
Copy Markdown
Author

@CodeRabbit review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 13, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/mqt/predictor/rl/predictor.py (1)

185-193: ⚠️ Potential issue | 🟡 Minor

Use a Google-style docstring for the new public parameter.

rl_compile() still documents parameters under Arguments:. Please switch this updated API docstring to Google style (Args: / Returns: / Raises:) and keep tracer_output_path documented there.

As per coding guidelines: "**/*.py: MUST use Google-style docstrings in Python code"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/mqt/predictor/rl/predictor.py` around lines 185 - 193, The rl_compile
docstring currently uses an "Arguments:" block; change it to Google-style
docstring sections by replacing "Arguments:" with "Args:" and converting the
parameter descriptions into Google-style parameter lines (e.g., qc:, device:,
figure_of_merit:, predictor_singleton:, tracer_output_path:), add a "Returns:"
section describing the function's return value and a "Raises:" section if
applicable, and ensure tracer_output_path is documented under Args exactly as
the new public parameter; update the top summary and any examples to remain
consistent with the rl_compile function/method name and signatures.
♻️ Duplicate comments (3)
CHANGELOG.md (1)

17-17: ⚠️ Potential issue | 🟡 Minor

Add the missing [#641] link definition.

Line 17 now references [#641], but the PR links block still does not define that reference, so the changelog renders an unresolved link. Please add the [#641]: …/pull/641 entry alongside the other PR links.

Based on learnings: "In the munich-quantum-toolkit/yaqs project, changelog entries follow the template: '- $TITLE (#$NUMBER) (AUTHOR)'. Issue references should not be included in changelog entries; the PR number is sufficient for traceability."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@CHANGELOG.md` at line 17, Add a missing PR link definition for the reference
`[`#641`]` used in CHANGELOG.md: open the PR links block near the other
pull-request link definitions and add an entry for `[`#641`]` pointing to the
repository pull URL (e.g., `https://github.com/<owner>/<repo>/pull/641`) using
the same link-definition format as the other entries so the `[`#641`]` reference
resolves correctly.
src/mqt/predictor/rl/predictor.py (1)

208-216: ⚠️ Potential issue | 🟠 Major

Restore the singleton tracer path in a finally block.

If compile_as_predicted() raises, Line 210's mutation survives and contaminates the shared predictor for the next call. The current cleanup also overwrites any pre-existing tracer path by forcing None on success. Capture the original value and restore it in finally.

Suggested fix
     else:
         predictor = predictor_singleton
-        predictor.env.tracer_output_path = tracer_output_path
-
-    result = predictor.compile_as_predicted(qc)
-
-    # Reset tracer path to prevent leakage to subsequent calls
-    if predictor_singleton is not None:
-        predictor.env.tracer_output_path = None
-
-    return result
+        original_tracer_output_path = predictor.env.tracer_output_path
+        predictor.env.tracer_output_path = tracer_output_path
+        try:
+            return predictor.compile_as_predicted(qc)
+        finally:
+            predictor.env.tracer_output_path = original_tracer_output_path
+
+    return predictor.compile_as_predicted(qc)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/mqt/predictor/rl/predictor.py` around lines 208 - 216, The code mutates
predictor.env.tracer_output_path before calling
predictor.compile_as_predicted(qc) without safe restoration on exception and
currently forces None on success; capture the original value (orig =
predictor.env.tracer_output_path) before assigning tracer_output_path, then
perform the call inside a try block and restore predictor.env.tracer_output_path
= orig in a finally block (guarding any restores behind
predictor_singleton/predictor existence) so the singleton’s previous tracer path
is preserved whether compile_as_predicted succeeds or raises.
tests/compilation/test_tracer.py (1)

47-49: ⚠️ Potential issue | 🟡 Minor

Assert that the trace reaches a terminal step.

These checks still pass if only the initial baseline snapshot is serialized. Please add an assertion for at least one later step and verify that the final recorded step is terminal so this test covers full-episode export, not just tracer initialization.

Suggested assertion update
     assert len(trace_data["steps"]) > 0, "Tracer did not record any compilation steps."
     assert trace_data["steps"][0]["action"] == "Baseline"
     assert trace_data["schema_version"] == "1.0.0"
+    assert len(trace_data["steps"]) > 1, "Tracer did not record any post-baseline steps."
+    assert trace_data["steps"][-1]["is_terminal"] is True
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/compilation/test_tracer.py` around lines 47 - 49, The test only
verifies the baseline snapshot; update it to assert the trace contains more than
one step (e.g., assert len(trace_data["steps"]) > 1) and then assert the final
step is terminal by checking the last step object (trace_data["steps"][-1]) has
either a terminal flag set (step["terminal"] is True) or an action indicating
termination (step["action"] == "Terminal"); add these two assertions alongside
the existing checks for trace_data and schema_version.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/mqt/predictor/rl/tracer.py`:
- Around line 237-244: The save_to_json method assumes the parent directory
exists; modify save_to_json (function save_to_json in tracer.py) to ensure the
output directory is created before opening the file: resolve filepath to a Path,
call .parent.mkdir(parents=True, exist_ok=True) (but avoid creating a parent for
root/single-file cases) and then proceed to open the file and
json.dump(asdict(self), ...). This ensures paths like
"artifacts/traces/run.json" won't raise FileNotFoundError.

---

Outside diff comments:
In `@src/mqt/predictor/rl/predictor.py`:
- Around line 185-193: The rl_compile docstring currently uses an "Arguments:"
block; change it to Google-style docstring sections by replacing "Arguments:"
with "Args:" and converting the parameter descriptions into Google-style
parameter lines (e.g., qc:, device:, figure_of_merit:, predictor_singleton:,
tracer_output_path:), add a "Returns:" section describing the function's return
value and a "Raises:" section if applicable, and ensure tracer_output_path is
documented under Args exactly as the new public parameter; update the top
summary and any examples to remain consistent with the rl_compile
function/method name and signatures.

---

Duplicate comments:
In `@CHANGELOG.md`:
- Line 17: Add a missing PR link definition for the reference `[`#641`]` used in
CHANGELOG.md: open the PR links block near the other pull-request link
definitions and add an entry for `[`#641`]` pointing to the repository pull URL
(e.g., `https://github.com/<owner>/<repo>/pull/641`) using the same
link-definition format as the other entries so the `[`#641`]` reference resolves
correctly.

In `@src/mqt/predictor/rl/predictor.py`:
- Around line 208-216: The code mutates predictor.env.tracer_output_path before
calling predictor.compile_as_predicted(qc) without safe restoration on exception
and currently forces None on success; capture the original value (orig =
predictor.env.tracer_output_path) before assigning tracer_output_path, then
perform the call inside a try block and restore predictor.env.tracer_output_path
= orig in a finally block (guarding any restores behind
predictor_singleton/predictor existence) so the singleton’s previous tracer path
is preserved whether compile_as_predicted succeeds or raises.

In `@tests/compilation/test_tracer.py`:
- Around line 47-49: The test only verifies the baseline snapshot; update it to
assert the trace contains more than one step (e.g., assert
len(trace_data["steps"]) > 1) and then assert the final step is terminal by
checking the last step object (trace_data["steps"][-1]) has either a terminal
flag set (step["terminal"] is True) or an action indicating termination
(step["action"] == "Terminal"); add these two assertions alongside the existing
checks for trace_data and schema_version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1b7e76b5-f069-431f-8d6a-6a120d6357f3

📥 Commits

Reviewing files that changed from the base of the PR and between 6f2784a and d0f0506.

📒 Files selected for processing (4)
  • CHANGELOG.md
  • src/mqt/predictor/rl/predictor.py
  • src/mqt/predictor/rl/tracer.py
  • tests/compilation/test_tracer.py

Comment thread src/mqt/predictor/rl/tracer.py
- now also checks semantics of the first and last compilation steps
- now also checks structural integrity of the compilation steps
@linus-hologram
Copy link
Copy Markdown
Author

@CodeRabbit review

@linus-hologram
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 14, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/compilation/test_tracer.py`:
- Around line 29-30: Update the docstring for the test function
test_compilation_tracer_generates_valid_json to follow Google-style formatting:
replace the one-line summary string with a multi-line docstring containing a
short description and an Args: section describing the tmp_path parameter (type
Path) and a Returns: section if appropriate (or omit if None), ensuring proper
indentation and blank line separation per Google-style conventions.
- Around line 34-45: You declared figure_of_merit = "expected_fidelity" but
still pass the literal "expected_fidelity" into Predictor(...) and
qcompile(...); update those call sites to use the figure_of_merit variable
instead (i.e., Predictor(figure_of_merit=figure_of_merit, ...) and qcompile(...,
figure_of_merit=figure_of_merit, ...)) so model training and compilation use the
same variable-driven value (refer to Predictor, qcompile, model_name,
model_path, and trace_file to locate the calls).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 88e76872-f756-4be9-b3cf-a9541f77d9f2

📥 Commits

Reviewing files that changed from the base of the PR and between a84658d and e4d03c4.

📒 Files selected for processing (1)
  • tests/compilation/test_tracer.py

Comment thread tests/compilation/test_tracer.py Outdated
Comment thread tests/compilation/test_tracer.py
@linus-hologram
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 14, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Collaborator

@flowerthrower flowerthrower left a comment

Choose a reason for hiding this comment

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

Dear @linus-hologram, this looks really nice and clean already. I left a few minor comments. Should be easy to implement. Thank you for this nice work!

Comment thread src/mqt/predictor/rl/tracer.py Outdated
Comment thread src/mqt/predictor/rl/predictorenv.py Outdated
Comment thread src/mqt/predictor/rl/tracer.py
Comment thread tests/compilation/test_tracer.py
- separate method inside predictorenv.py that handles collection of data for tracing
- qasm3 circuit strings are now used instead of qasm2
- tracer now collects all possible figures of merit
- included cleaner methods for calculating the supported figures of merit and a draft for a rewrite of the calculate_reward function
- included according tests
@linus-hologram
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 10

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/mqt/predictor/rl/predictorenv.py`:
- Around line 648-706: Remove the dead commented-out calculate_reward_new block
(the MARK header and the commented method body) from predictorenv.py; instead,
either add a single-line TODO with a ticket/issue reference or create a GitHub
issue to track a future refactor of calculate_reward, and ensure existing reward
dispatch is implemented by delegating to calculate_expected_fidelity,
calculate_estimated_success_probability, calculate_critical_depth, and
calculate_estimated_hellinger_distance as appropriate in a separate PR.
- Around line 456-470: The logs are using a hard-coded 0.0 instead of the
computed reward_val; update the two _log_step_reward calls to pass the computed
reward_val (the variable set by calculate_reward) rather than 0.0 — one inside
the reward_function == "estimated_hellinger_distance" branch (where reward_val
is set from calculate_reward) and the other in the main branch where reward_val
is computed before calling _collect_tracer_data; adjust both
_log_step_reward(...) calls to use reward_val so logged/terminal rewards match
what is passed to _collect_tracer_data.
- Around line 304-376: Remove the unnecessary trailing `return` at the end of
_collect_tracer_data (it returns None implicitly) and instead initialize/cache
the Hellinger model once in __init__ when tracing is enabled (tracer_output_path
is not None) and reward_function != "estimated_hellinger_distance" rather than
re-loading it inside reset(); move the joblib.load call currently in reset()
into __init__, store the model on self.hellinger_model, and update reset() to
use the cached self.hellinger_model (refer to methods _collect_tracer_data,
reset, __init__ and symbol joblib.load / self.hellinger_model).
- Around line 441-452: The code path that handles `_apply_and_update` returning
None currently forces done=True and calls `_collect_tracer_data`, which triggers
`tracer.save_to_json` and makes aborted episodes indistinguishable from normal
terminations; update this by (a) adding an explicit status flag (e.g.,
status="aborted" or aborted=True) to `_collect_tracer_data` and its downstream
`tracer.save_to_json` call so aborted traces are labeled, or (b) gate the call
to `tracer.save_to_json` inside `_collect_tracer_data` (or where
`tracer.save_to_json` is invoked) to only run when `action_name` equals the
explicit terminate action (e.g., "terminate"), and ensure the return path from
this `_apply_and_update`-None branch still returns the observation and done flag
but does not produce a saved JSON that looks like a successful terminal episode;
modify `_apply_and_update`, `_collect_tracer_data`, and the tracer save logic
accordingly to propagate the new status flag or conditional save behavior.

In `@src/mqt/predictor/rl/tracer.py`:
- Around line 28-38: The TopologyEdge dataclass currently uses misleading field
names control and target; rename these fields to neutral names (e.g., source and
target or source and destination) in the TopologyEdge class and update all
references to TopologyEdge.control and TopologyEdge.target (including any JSON
serialization/deserialization, schema producers/consumers, and unit tests) to
use the new names (TopologyEdge.source and TopologyEdge.target). Ensure any code
that constructs or parses topology JSON is updated to the new field names and
that saved schemas are versioned or documented to reflect the change.
- Around line 294-299: _extract_float currently only handles ints and
subscriptable arrays and will raise on Python floats or 0-d NumPy scalars;
change it to normalize the input with np.asarray(val) and then return a float
using .item() for single-element scalars or .ravel()[0] (or reshape(-1)[0]) for
arrays with >=1 elements, removing the isinstance(val, int) branch; also ensure
numpy is imported at runtime (not only under TYPE_CHECKING) so np.asarray is
available.
- Around line 263-292: The DeviceMetadata.description field is typed as str but
Target.description can be Optional[str]; update _extract_device_metadata to
handle None by providing a fallback string (e.g., empty string or a default like
"unknown device") when assigning device.description to
DeviceMetadata.description; modify the return construction in
_extract_device_metadata so DeviceMetadata(description=...) uses
device.description if present else the chosen default to satisfy the type
contract.

In `@tests/compilation/test_tracer.py`:
- Around line 86-97: DeviceMetadata(**trace_data["device"]) and
CompilationStep(**trace_data["steps"][0]) only catch missing/unexpected keys via
kwargs coercion but won't detect when the dataclass adds a new field with a
default (old JSON missing that key will still validate); update the test to
explicitly assert that the JSON object's key sets exactly match the dataclass
field names: derive expected fields via dataclasses.fields(DeviceMetadata) and
dataclasses.fields(CompilationStep) and compare them against
trace_data["device"].keys() and trace_data["steps"][i].keys() (also check
last_step_data), failing the test on any missing or extra keys, or alternatively
generate/validate against a JSON Schema produced from those dataclasses to
enforce strict contract parity.
- Around line 83-84: The failing assertion is order-dependent because
CompilationTracer._collect_tracer_data sets self.hellinger_model in reset() when
get_hellinger_model_path(self.device).is_file(); update the test in
tests/compilation/test_tracer.py to avoid relying on absence of a persisted
model: either (A) replace the strict assert fom_data.get("hellinger_distance")
is None with a structural check such as "hellinger_distance" in fom_data and, if
present, validate its keys/value types (e.g., contains 'value' and 'kind'), or
(B) before exercising CompilationTracer.reset()/_collect_tracer_data explicitly
remove or move get_hellinger_model_path(device) so the model file cannot exist,
ensuring deterministic fallback to None; reference
CompilationTracer._collect_tracer_data, CompilationTracer.reset, and
get_hellinger_model_path(device) when making the change.
- Around line 37-48: The variable figure_of_merit is currently untyped (inferred
as str) but is passed to Predictor and rl_compile which expect a Literal value;
fix by annotating it as a Literal literal (e.g., change the binding to:
figure_of_merit: typing.Literal["expected_fidelity"] = "expected_fidelity") or
import and use the repository alias from ty if available, ensuring the narrow
type is used where figure_of_merit is passed to Predictor and rl_compile so the
type-checker accepts the call sites.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0b91a29a-9740-4cd0-97d9-5cdfb6d6c1d3

📥 Commits

Reviewing files that changed from the base of the PR and between e4d03c4 and 2424d3c.

📒 Files selected for processing (3)
  • src/mqt/predictor/rl/predictorenv.py
  • src/mqt/predictor/rl/tracer.py
  • tests/compilation/test_tracer.py

Comment thread src/mqt/predictor/rl/predictorenv.py Outdated
Comment thread src/mqt/predictor/rl/predictorenv.py
Comment thread src/mqt/predictor/rl/predictorenv.py
Comment thread src/mqt/predictor/rl/predictorenv.py Outdated
Comment thread src/mqt/predictor/rl/tracer.py
Comment thread src/mqt/predictor/rl/tracer.py
Comment thread src/mqt/predictor/rl/tracer.py
Comment thread tests/compilation/test_tracer.py
Comment thread tests/compilation/test_tracer.py Outdated
Comment thread tests/compilation/test_tracer.py
Comment thread src/mqt/predictor/rl/predictorenv.py
Comment thread src/mqt/predictor/rl/predictorenv.py Outdated
Copy link
Copy Markdown
Collaborator

@flowerthrower flowerthrower left a comment

Choose a reason for hiding this comment

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

Thanks for the continued work. Eine letzte Runde und dann sollte es passen.

Comment thread src/mqt/predictor/rl/predictorenv.py
Comment thread src/mqt/predictor/rl/predictorenv.py Outdated
Comment thread src/mqt/predictor/rl/predictorenv.py Outdated
@linus-hologram
Copy link
Copy Markdown
Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/mqt/predictor/rl/predictorenv.py`:
- Around line 455-469: When reward_function == "estimated_hellinger_distance"
compute the current Hellinger value each step by calling
calculate_reward(mode="exact") (do not force non-terminal to 0.0), derive the
shaped step reward as the delta from prev_reward (or use terminal semantics if
done), update prev_reward and prev_reward_kind with the current value/kind,
avoid mutating self.state._layout (export a copy of layout metadata if needed
for observation/tracing), then call _log_step_reward and _collect_tracer_data
passing the actual current Hellinger FOM (fom_value) and correct fom_kind
instead of serializing 0.0.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: f36fc7cd-23a2-4e0d-a442-e9e2d1f009f7

📥 Commits

Reviewing files that changed from the base of the PR and between 2424d3c and 197ebc5.

📒 Files selected for processing (2)
  • src/mqt/predictor/rl/predictorenv.py
  • tests/compilation/test_tracer.py

Comment thread src/mqt/predictor/rl/predictorenv.py
@flowerthrower
Copy link
Copy Markdown
Collaborator

LGTM!

@flowerthrower flowerthrower merged commit e6f922e into munich-quantum-toolkit:qce-experiments Apr 21, 2026
8 of 13 checks passed
@linus-hologram linus-hologram deleted the thesis-predictor-visualization branch April 21, 2026 14:26
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.

2 participants