Skip to content

Bump aGrUM requirement to 3, add tests, fix correctness issues - #105

Closed
phwuil wants to merge 8 commits into
openturns:masterfrom
phwuil:v0.15
Closed

phwuil wants to merge 8 commits into
openturns:masterfrom
phwuil:v0.15

Conversation

@phwuil

@phwuil phwuil commented Jul 20, 2026 •

Copy link
Copy Markdown
Collaborator
  • Bump aGrUM requirement to 3, clean up NamedDAG/TabuList
  • Fix small correctness issues found in audit (JunctionTreeBernsteinCopula, NamedJunctionTree, Python docstrings/bindings)
  • Deduplicate structure-learning helpers, validate samples, wrap rank_ pointers (ContinuousMIIC, ContinuousPC, TabuList, Greater, Utils)
  • Add test coverage for previously untested classes and error paths (C++ and Python)
  • Bump version to 0.15
  • Add root Makefile wrapping the CMake build

Summary by CodeRabbit

  • New Features
    • Added NamedDAG name-to-ID lookup support.
    • Added standardized build, test, and cleanup commands.
    • Added OpenMP support and compatibility with aGrUM 3.
  • Bug Fixes
    • Improved validation and clear errors for empty samples and invalid settings.
    • Ensured copula updates and numerical ranges refresh after bin changes.
    • Improved graph derivation and latent relationship handling.
  • Documentation
    • Updated configuration-key documentation and package version to 0.15.
  • Tests
    • Expanded C++ and Python coverage for graph learning, copulas, statistical tests, and utilities.

phwuil added 6 commits July 19, 2026 19:39
- CMakeLists.txt: require aGrUM >= 3, find OpenMP
- Drop unused NamedDAG.hxx include from CorrectedMutualInformation.hxx
- Clarify NamedJunctionTree's variable-id vs clique-id name mapping
- Refactor NamedDAG.cxx and TabuList.cxx
- Update expected test outputs accordingly
- Add detailed code audit (audit.md)
- JunctionTreeBernsteinCopula::setBinNumber() now recomputes cached state
- NamedJunctionTree: replace assert() with an exception (release-safe)
- Fix stale ResourceMap key name in factory docstring
- Fix copy-pasted SWIG file header comment
- Document the SWIG warning-suppression pragma
…pointers

- Share namesFromData/idFromName/learnDAG/GetK via Utils across
  ContinuousPC, ContinuousMIIC and TabuList
- Extract recordLatentCoupleIfNeeded() and legalChangesForPair() to
  remove duplicated blocks in ContinuousMIIC/TabuList
- Reject empty samples in ContinuousTTest/CorrectedMutualInformation
  instead of silently propagating NaN
- Reject TabuList(restarts=0) instead of underflowing
- Wrap rank_'s shared_ptr<tuple<...>> in a RankedTriple class with
  named accessors (gum::Heap requires copyable elements, so
  unique_ptr is not an option)
- Add license/OTAGRUM_API to Greater.hxx, document why DeriveDAG is
  hidden from SWIG
- Add C++ tests for Greater and JunctionTreeBernsteinCopulaFactory
- Add Python tests for ContinuousTTest, CorrectedMutualInformation,
  NamedDAG and JunctionTreeBernsteinCopulaFactory
- Reactivate disabled Utils.py tests and ContinuousBayesianNetwork's
  genereData()
- Add empty-sample/invalid-input exception checks to ContinuousPC,
  ContinuousMIIC and TabuList Python tests
Targets: cpp, py, cpptest, pytest, all, clean.
@coderabbitai

coderabbitai Bot commented Jul 20, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@phwuil, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3270afa6-47c5-49b2-82b5-7d2719004223

📥 Commits

Reviewing files that changed from the base of the PR and between e59aeab and 94ecb39.

📒 Files selected for processing (1)
  • lib/src/Utils.cxx
📝 Walkthrough

Walkthrough

The change updates the project to version 0.15, adds standardized CMake build targets, centralizes graph and estimator utilities, revises learning algorithms and validation, and expands C++ and Python test coverage.

Changes

Release and build updates

Layer / File(s) Summary
Release metadata and build orchestration
AUTHORS, CMakeLists.txt, Makefile, VERSION, distro/...
Release metadata moves to 0.15, CMake requires OpenMP and aGrUM 3, and Makefile targets standardize build, test, and cleanup commands.

Core library changes

Layer / File(s) Summary
Shared graph and ranking contracts
lib/src/otagrum/Utils.hxx, lib/src/Utils.cxx, lib/src/otagrum/NamedDAG.hxx, lib/src/NamedDAG.cxx, lib/src/otagrum/Greater.hxx, lib/src/Greater.cxx
Shared utilities handle descriptions, name lookup, DAG derivation, and bin counts; NamedDAG stores names in the graph; ranked triples replace tuple pointers.
Learning algorithm integration
lib/src/ContinuousMIIC.*, lib/src/ContinuousPC.cxx, lib/src/TabuList.*
MIIC, PC, and TabuList use the shared helpers, value-based ranking, consolidated latent-couple recording, and refactored legal graph-change handling.
Estimator and graph runtime validation
lib/src/ContinuousTTest.cxx, lib/src/CorrectedMutualInformation.*, lib/src/JunctionTreeBernsteinCopula.cxx, lib/src/NamedJunctionTree.*
Empty samples and invalid restart counts are validated, shared bin-count computation is used, bin-number changes refresh derived state, and invalid junction-tree ordering raises an exception.

Validation and interfaces

Layer / File(s) Summary
C++ test coverage and expected outputs
lib/test/*
C++ comparator and copula-factory tests are added, existing test execution is expanded, and expected graph, Bayesian-network, and table outputs are updated.
Python interfaces and test coverage
python/src/*, python/test/*
Python version and documentation are updated; post-install registrations and tests cover empty inputs, estimator behavior, named DAGs, TabuList validation, copula factories, and utility output.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Learner
  participant Utils
  participant AGrUM
  participant NamedDAG
  Learner->>Utils: resolve names and derive DAG
  Utils->>AGrUM: propagate PDAG with MeekRules
  AGrUM-->>Utils: derived DAG
  Utils->>NamedDAG: construct named graph
  NamedDAG-->>Learner: return learned DAG
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main changes: aGrUM 3 upgrade, added tests, and correctness fixes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
Makefile (1)

3-5: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider adding a standard test target.

To conform with standard Makefile conventions and address the static analysis warning, consider adding a test target that runs both cpptest and pytest.

♻️ Proposed refactor
-.PHONY: all cpp py cpptest pytest clean
+.PHONY: all cpp py cpptest pytest test clean
 
 all: cpp py
+
+test: cpptest pytest
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 3 - 5, Add a standard test target to the Makefile that
depends on and runs both existing cpptest and pytest targets, while preserving
their current behavior and declarations.

Source: Linters/SAST tools

python/test/t_ContinuousMIIC_std.py (1)

104-110: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Avoid catching blind exceptions in validation tests.
Across several test scripts, testEmptySampleRaises catches the base Exception class. This can inadvertently swallow unrelated errors—such as a NameError or AttributeError resulting from a typo inside the try block—causing the test to falsely pass even if the constructor wasn't called correctly. Consider catching the specific exception raised by OpenTURNS/SWIG.

  • python/test/t_ContinuousMIIC_std.py#L104-L110: Replace except Exception: with except (ValueError, RuntimeError): or the specific expected exception.
  • python/test/t_ContinuousPC_std.py#L49-L55: Replace except Exception: with except (ValueError, RuntimeError): or the specific expected exception.
  • python/test/t_ContinuousTTest_std.py#L39-L45: Replace except Exception: with except (ValueError, RuntimeError): or the specific expected exception.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/test/t_ContinuousMIIC_std.py` around lines 104 - 110, Replace the
broad exception handling in testEmptySampleRaises with ValueError, RuntimeError,
or the specific expected OpenTURNS/SWIG exception in
python/test/t_ContinuousMIIC_std.py:104-110,
python/test/t_ContinuousPC_std.py:49-55, and
python/test/t_ContinuousTTest_std.py:39-45, so unrelated errors are not
swallowed.

Source: Linters/SAST tools

lib/src/ContinuousMIIC.cxx (1)

341-353: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

Route the latent-couple appends through the helper
The four orientation-propagation branches still append directly instead of using recordLatentCoupleIfNeeded(...); centralizing that bookkeeping keeps the handling consistent with the other paths.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@lib/src/ContinuousMIIC.cxx` around lines 341 - 353, The four
orientation-propagation branches should stop appending latent couples directly
and call ContinuousMIIC::recordLatentCoupleIfNeeded(...) instead. Replace each
direct latent_couples_ append with the helper, passing the corresponding node
pair, while preserving each branch’s existing orientation logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/src/ContinuousBayesianNetworkFactory_doc.i`:
- Around line 42-43: Fix the spacing in the documentation text for
ContinuousBayesianNetworkFactory-UseBetaCopula by adding a space before the
:class:`openturns.BernsteinCopulaFactory` Sphinx directive, preserving the
existing wording and formatting otherwise.

---

Nitpick comments:
In `@lib/src/ContinuousMIIC.cxx`:
- Around line 341-353: The four orientation-propagation branches should stop
appending latent couples directly and call
ContinuousMIIC::recordLatentCoupleIfNeeded(...) instead. Replace each direct
latent_couples_ append with the helper, passing the corresponding node pair,
while preserving each branch’s existing orientation logic.

In `@Makefile`:
- Around line 3-5: Add a standard test target to the Makefile that depends on
and runs both existing cpptest and pytest targets, while preserving their
current behavior and declarations.

In `@python/test/t_ContinuousMIIC_std.py`:
- Around line 104-110: Replace the broad exception handling in
testEmptySampleRaises with ValueError, RuntimeError, or the specific expected
OpenTURNS/SWIG exception in python/test/t_ContinuousMIIC_std.py:104-110,
python/test/t_ContinuousPC_std.py:49-55, and
python/test/t_ContinuousTTest_std.py:39-45, so unrelated errors are not
swallowed.
🪄 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 77cf8568-4022-42e0-af01-4ca16c0e0cfb

📥 Commits

Reviewing files that changed from the base of the PR and between f7a55c7 and e59aeab.

📒 Files selected for processing (54)
  • AUTHORS
  • CMakeLists.txt
  • Makefile
  • VERSION
  • distro/debian/changelog
  • distro/rpm/otagrum.spec
  • lib/src/ContinuousMIIC.cxx
  • lib/src/ContinuousPC.cxx
  • lib/src/ContinuousTTest.cxx
  • lib/src/CorrectedMutualInformation.cxx
  • lib/src/Greater.cxx
  • lib/src/JunctionTreeBernsteinCopula.cxx
  • lib/src/NamedDAG.cxx
  • lib/src/NamedJunctionTree.cxx
  • lib/src/TabuList.cxx
  • lib/src/Utils.cxx
  • lib/src/otagrum/ContinuousMIIC.hxx
  • lib/src/otagrum/CorrectedMutualInformation.hxx
  • lib/src/otagrum/Greater.hxx
  • lib/src/otagrum/NamedDAG.hxx
  • lib/src/otagrum/NamedJunctionTree.hxx
  • lib/src/otagrum/TabuList.hxx
  • lib/src/otagrum/Utils.hxx
  • lib/test/CMakeLists.txt
  • lib/test/t_ContinuousBayesianNetwork_std.cxx
  • lib/test/t_ContinuousBayesianNetwork_std.expout
  • lib/test/t_ContinuousPC_std.expout
  • lib/test/t_Greater_std.cxx
  • lib/test/t_Greater_std.expout
  • lib/test/t_JunctionTreeBernsteinCopulaFactory_std.cxx
  • lib/test/t_JunctionTreeBernsteinCopulaFactory_std.expout
  • lib/test/t_Utils_std.expout
  • python/src/ContinuousBayesianNetworkFactory_doc.i
  • python/src/NamedDAG.i
  • python/src/NamedDAG_doc.i
  • python/src/__init__.py
  • python/src/otagrum_agrum.i
  • python/test/CMakeLists.txt
  • python/test/t_ContinuousMIIC_std.expout
  • python/test/t_ContinuousMIIC_std.py
  • python/test/t_ContinuousPC_std.expout
  • python/test/t_ContinuousPC_std.py
  • python/test/t_ContinuousTTest_std.expout
  • python/test/t_ContinuousTTest_std.py
  • python/test/t_CorrectedMutualInformation_std.expout
  • python/test/t_CorrectedMutualInformation_std.py
  • python/test/t_JunctionTreeBernsteinCopulaFactory_std.expout
  • python/test/t_JunctionTreeBernsteinCopulaFactory_std.py
  • python/test/t_NamedDAG_std.expout
  • python/test/t_NamedDAG_std.py
  • python/test/t_TabuList_std.expout
  • python/test/t_TabuList_std.py
  • python/test/t_Utils_std.expout
  • python/test/t_Utils_std.py
💤 Files with no reviewable changes (1)
  • lib/src/otagrum/CorrectedMutualInformation.hxx

Comment on lines +42 to 43
- *'ContinuousBayesianNetworkFactory-UseBetaCopula'* to indicate if the
estimated copula should be a Beta copula if a:class:`openturns.BernsteinCopulaFactory` is provided. Default value is *True*.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Fix spacing for Sphinx directive.

The :class: directive on line 43 is missing a space before it, which will prevent Sphinx from rendering the cross-reference correctly.

📝 Proposed fix
-      estimated copula should be a Beta copula if a:class:`openturns.BernsteinCopulaFactory` is provided. Default value is *True*.
+      estimated copula should be a Beta copula if a :class:`~openturns.BernsteinCopulaFactory` is provided. Default value is *True*.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- *'ContinuousBayesianNetworkFactory-UseBetaCopula'* to indicate if the
estimated copula should be a Beta copula if a:class:`openturns.BernsteinCopulaFactory` is provided. Default value is *True*.
- *'ContinuousBayesianNetworkFactory-UseBetaCopula'* to indicate if the
estimated copula should be a Beta copula if a :class:`~openturns.BernsteinCopulaFactory` is provided. Default value is *True*.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/src/ContinuousBayesianNetworkFactory_doc.i` around lines 42 - 43, Fix
the spacing in the documentation text for
ContinuousBayesianNetworkFactory-UseBetaCopula by adding a space before the
:class:`openturns.BernsteinCopulaFactory` Sphinx directive, preserving the
existing wording and formatting otherwise.

agrum's BIFReader.h/BIFWriter.h pull in <windows.h> on mingw, which
#defines GetClassName to GetClassNameA/W. In unity builds this leaks
into later translation units (e.g. NamedDAG.cxx), breaking OT's
CLASSNAMEINIT macro whose declaration/definition then mismatch.
@jschueller jschueller mentioned this pull request Jul 20, 2026
Comment thread Makefile Outdated
cd $(BUILD_DIR) && ctest --output-on-failure -R '^pyinstallcheck_'

clean:
rm -rf $(BUILD_DIR)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

imho this is redundant with CMakePresets file and should be dropped

Comment thread CMakeLists.txt
message (STATUS "Found OpenTURNS: ${OpenTURNS_DIR} (found version \"${OpenTURNS_VERSION}\")")

find_package (aGrUM 2 CONFIG REQUIRED)
find_package (OpenMP)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

looks like an openmp public dependency should be added in agrum cmake config with find_dependencies instead

otagrum.ContinuousMIIC(ot.Sample())
print("empty sample raises : fail (no exception)")
except Exception:
print("empty sample raises : OK")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

use openturns.testing.assert_raises instead

otagrum.ContinuousTTest(ot.Sample())
print("empty sample raises : fail (no exception)")
except Exception:
print("empty sample raises : OK")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

assert_raises here too

try:
otagrum.CorrectedMutualInformation(ot.Sample())
print("empty sample raises : fail (no exception)")
except Exception:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

assert_raises

try:
otagrum.NamedDAG(bn)
print("non contiguous ids raises : fail (no exception)")
except Exception:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

assert_raises

try:
otagrum.TabuList(data, restarts=0)
print("restarts=0 raises : fail (no exception)")
except Exception:

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

assert_raises

@jschueller

Copy link
Copy Markdown
Member

included in #106

@jschueller jschueller closed this Jul 20, 2026
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