Skip to content

Fix GAM splines_non_negative missing from actual_params by correcting boolean[] parameter serialization - #16862

Open
maurever with Copilot wants to merge 4 commits into
rel-3.46.0from
copilot/fix-splines-non-negative-output
Open

Fix GAM splines_non_negative missing from actual_params by correcting boolean[] parameter serialization#16862
maurever with Copilot wants to merge 4 commits into
rel-3.46.0from
copilot/fix-splines-non-negative-output

Conversation

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor

GH Issue: #16602

GAM models were returning splines_non_negative as None in actual_params even when explicitly set. The issue was in core parameter JSON serialization: boolean[] values were wrapped but emitted as null.

  • Root cause

    • water.IcedWrapper did not correctly support boolean[] in JSON output (writeUnwrappedJSON returned null for boolean arrays).
    • Model parameter metadata relies on this wrapper for polymorphic actual_value serialization, so splines_non_negative was dropped to None in clients.
  • Changes made

    • h2o-core/src/main/java/water/IcedWrapper.java
      • Added full boolean[] support in IcedWrapper:
        • store wrapped boolean arrays (b_ar)
        • return boolean arrays from get()
        • include boolean array handling in toString()
        • serialize boolean arrays as JSON booleans ([true,false,...]) instead of null
    • h2o-core/src/test/java/water/IcedWrapperTest.java
      • Added targeted unit coverage for:
        • round-trip retrieval of wrapped boolean[]
        • JSON output format for wrapped boolean[]
    • h2o-py/tests/testdir_algos/gam/pyunit_gam_splines_non_negative_actual_params.py
      • Added a GAM regression test that trains with splines_non_negative=[True, False] and verifies the value is preserved in:
        • model.actual_params["splines_non_negative"]
        • model.parms["splines_non_negative"]["actual_value"]
  • Illustrative behavior

    IcedWrapper w = new IcedWrapper(new boolean[]{true, false});
    String json = new String(w.writeUnwrappedJSON(new AutoBuffer()).buf());
    // before: null
    // after:  [true,false]

[!WARNING]

Copilot AI linked an issue May 21, 2026 that may be closed by this pull request
Copilot AI changed the title [WIP] Fix H2O GAM splines_non_negative parameter output Fix GAM splines_non_negative missing from actual_params by correcting boolean[] parameter serialization May 21, 2026
Copilot AI requested a review from maurever May 21, 2026 11:48
@maurever

Copy link
Copy Markdown
Contributor

@copilot , changes look good. Could you add a test where the actual parameters in the GAM algorithm are correct? Especially, the splines_non_negative parameter is correct in actual_params.

Copilot AI commented May 26, 2026

Copy link
Copy Markdown
Contributor Author

@copilot , changes look good. Could you add a test where the actual parameters in the GAM algorithm are correct? Especially, the splines_non_negative parameter is correct in actual_params.

Added in commit 8776e30.

I introduced a focused GAM regression test at h2o-py/tests/testdir_algos/gam/pyunit_gam_splines_non_negative_actual_params.py that trains a GAM with splines_non_negative=[True, False] and asserts this value is preserved in both actual_params["splines_non_negative"] and parms["splines_non_negative"]["actual_value"].

@sonarqubecloud

Copy link
Copy Markdown

@maurever maurever added this to the 3.46.0.12 milestone May 27, 2026
@maurever
maurever changed the base branch from master to rel-3.46.0 May 27, 2026 14:08
@maurever
maurever force-pushed the copilot/fix-splines-non-negative-output branch from 8776e30 to 8f8b6fb Compare July 7, 2026 12:34
@maurever
maurever marked this pull request as ready for review July 7, 2026 12:35

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 fixes incorrect JSON serialization of boolean[] values in water.IcedWrapper, which caused certain model parameters (notably GAM’s splines_non_negative) to appear as None/missing in actual_params despite being explicitly set. The change improves parameter metadata fidelity for clients that rely on IcedWrapper.writeUnwrappedJSON for polymorphic actual_value serialization.

Changes:

  • Add first-class boolean[] support to water.IcedWrapper (store, retrieve via get(), stringify, and serialize as a JSON boolean array).
  • Add JUnit coverage validating boolean[] round-trip via get() and exact JSON output.
  • Add a Python regression test ensuring GAM preserves splines_non_negative in both actual_params and parms[..]["actual_value"].

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
h2o-core/src/main/java/water/IcedWrapper.java Implements boolean[] wrapping and correct unwrapped JSON serialization ([true,false]), preventing loss of boolean-array parameter values in model metadata.
h2o-core/src/test/java/water/IcedWrapperTest.java Adds targeted unit tests for boolean[] retrieval and JSON output to prevent regressions in core serialization behavior.
h2o-py/tests/testdir_algos/gam/pyunit_gam_splines_non_negative_actual_params.py Adds an end-to-end GAM regression test validating client-visible parameter preservation in actual_params and parameter schema metadata.

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

tomasfryda
tomasfryda previously approved these changes Jul 7, 2026

@tomasfryda tomasfryda left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM, thank you @maurever !

@valenad1

valenad1 commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Thank you for the fix!

Suggestion: reuse the existing AutoBuffer.putJSONAZ(boolean[]) instead of a new helper

The fix is correct, but writeBooleanArrayAsJSON duplicates logic that already exists in AutoBuffer.putJSONAZ(boolean[]) (AutoBuffer.java:1791) — same [, comma-join, ] with null → putJNULL(), identical output. That's actually the method (added in 2015) that makes serializing boolean[] possible in the first place; it's just currently private.

Every other array case/if-else in writeUnwrappedJSON already delegates to an AutoBuffer.putJSONA* method (putJSONA4, putJSONA8, putJSONA8d, …), so the boolean[] case being an inline loop is the lone exception. It'd be more consistent to delegate too.

IcedWrapper is in the same water package as AutoBuffer, so this doesn't need public — just drop private to make it package-private, matching putJSONA4/putJSONA8/putJSONA4f:

// AutoBuffer.java:1791
AutoBuffer putJSONAZ(boolean[] b) {   // was: private

Then in IcedWrapper the helper can go away entirely:

else if (t.equals("Bo"))
  return ab.putJSONAZ(b_ar);

Not a blocker — the current code works — just a maintainability/consistency cleanup.

(Drafted with Claude Code.)

IcedWrapper.writeUnwrappedJSON duplicated logic already present in
AutoBuffer.putJSONAZ(boolean[]). Widen its visibility to package-private
(matching putJSONA4/putJSONA8/putJSONA4f).

Co-authored-by: Claude <noreply@anthropic.com>
@maurever
maurever requested a review from tomasfryda July 15, 2026 13:03
@maurever maurever removed this from the 3.46.0.12 milestone Jul 15, 2026
@maurever maurever added this to the 3.46.0.11 milestone Jul 15, 2026
@sonarqubecloud

Copy link
Copy Markdown

@maurever

Copy link
Copy Markdown
Contributor

@tomasfryda @valenad1, could you please review again? Thank you.

@maurever maurever modified the milestones: 3.46.0.11, 3.46.0.12 Jul 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

H2O GAM splines_non_negative parameter doesn't show in model output

5 participants