Skip to content

multivariadic mul - #407

Merged
thedavidmeister merged 2 commits into
mainfrom
2025-09-19-variadic-mul
Sep 19, 2025
Merged

multivariadic mul#407
thedavidmeister merged 2 commits into
mainfrom
2025-09-19-variadic-mul

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Sep 19, 2025

Copy link
Copy Markdown
Contributor

Motivation

Solution

Checks

By submitting this for review, I'm confirming I've done the following:

  • made this PR as small as possible
  • unit-tested any new functionality
  • linked any relevant issues or PRs
  • included screenshots (if this involves a front-end change)

Summary by CodeRabbit

  • Bug Fixes
    • Improved accuracy and consistency of decimal multiplication across single and multiple operands.
    • More reliable detection and handling of rounding/loss scenarios, reducing edge-case discrepancies for very large or small values.
    • Aligned runtime and reference multiplication paths to prevent rare mismatches in complex calculations.

@coderabbitai

coderabbitai Bot commented Sep 19, 2025

Copy link
Copy Markdown
Contributor

Walkthrough

Refactors LibOpMul to unpack Float operands to (signedCoefficient, exponent), multiply using LibDecimalFloatImplementation.mul across inputs, then repack with LibDecimalFloat.packLossy. Adds using LibDecimalFloat for Float;. Reference path updated similarly and captures but does not use the loss flag.

Changes

Cohort / File(s) Summary
Mul op refactor (unpack → impl.mul → packLossy)
src/lib/op/math/LibOpMul.sol
Added using LibDecimalFloat for Float;. Replaced direct LibDecimalFloat.mul usage with operand unpack() to (signedCoefficient, exponent), iterative LibDecimalFloatImplementation.mul(...) across inputs, and final LibDecimalFloat.packLossy(...). Reference function updated to capture (unused) loss flag.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor Caller
  participant LibOpMul
  participant FloatLib as LibDecimalFloat
  participant Impl as LibDecimalFloatImplementation

  Caller->>LibOpMul: run(inputs: Float[])
  LibOpMul->>FloatLib: unpack(a)
  FloatLib-->>LibOpMul: (coeffA, expA)
  LibOpMul->>FloatLib: unpack(b)
  FloatLib-->>LibOpMul: (coeffB, expB)
  LibOpMul->>Impl: mul(coeffA, expA, coeffB, expB)
  Impl-->>LibOpMul: (coeff, exp)
  loop accumulate remaining operands
    LibOpMul->>FloatLib: unpack(next)
    FloatLib-->>LibOpMul: (coeffN, expN)
    LibOpMul->>Impl: mul(coeff, exp, coeffN, expN)
    Impl-->>LibOpMul: (coeff, exp)
  end
  LibOpMul->>FloatLib: packLossy(coeff, exp)
  FloatLib-->>LibOpMul: (Float result, lossFlag)
  LibOpMul-->>Caller: Float result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • 2025 07 12 mul #355 — Similar LibOpMul refactor performing unpack → LibDecimalFloatImplementation.mul → packLossy on multiplication paths.
  • variadic add lint #406 — Related refactor applying the unpack/impl-mul/packLossy pattern across arithmetic operation libraries (e.g., add).

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "multivariadic mul" concisely and accurately describes the primary change — enabling variadic/multivariate multiplication — which matches the LibOpMul edits in the changeset that implement multi-operand multiplication via unpack/mul/pack logic. The title is short, specific, and directly related to the code changes rather than vague or off-topic. It conveys the main intent clearly for a teammate scanning history.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch 2025-09-19-variadic-mul

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

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c31f2f and 3d0b8e6.

⛔ Files ignored due to path filters (1)
  • src/generated/Rainterpreter.pointers.sol is excluded by !**/generated/**
📒 Files selected for processing (1)
  • src/lib/op/math/LibOpMul.sol (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: rainix (ubuntu-latest, test-wasm-build)
  • GitHub Check: rainix (macos-latest, rainix-rs-artifacts)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-static)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-artifacts)
  • GitHub Check: rainix (macos-latest, rainix-rs-test)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-artifacts)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-test)
  • GitHub Check: git-clean
🔇 Additional comments (7)
src/lib/op/math/LibOpMul.sol (7)

15-15: LGTM! Good use of the using directive.

Adding the using directive for LibDecimalFloat on Float type improves code readability by enabling method-style calls like a.unpack() instead of LibDecimalFloat.unpack(a).


33-36: The refactoring to unpacked arithmetic looks correct.

The change from direct multiplication to unpacking operands, multiplying coefficients/exponents via LibDecimalFloatImplementation.mul, and then repacking is a valid approach that provides more control over the multiplication process.


46-48: Consistent implementation in the loop.

The loop correctly unpacks each additional operand and accumulates the result using the same multiplication approach, maintaining consistency with the initial multiplication.


73-79: Reference implementation correctly mirrors the main logic.

The reference implementation properly follows the same unpacked arithmetic pattern as the main run function, ensuring consistency for testing purposes.


33-55: Precision-loss handling consistent across math ops

LibOpAdd and LibOpDiv follow the same unpack → LibDecimalFloatImplementation.add/div → LibDecimalFloat.packLossy accumulation pattern as LibOpMul, so the refactor is consistent.


55-55: Consider handling the loss flag from packLossy.

The packLossy function returns a tuple (Float, bool) where the boolean indicates whether the packing was lossless. Currently, the loss flag is being discarded. Consider whether this information should be used for debugging, logging, or error handling.


17-21: Approve — integrity supports variadic mul

Integrity enforces a minimum of 2 inputs; run and reference implementations iterate over N≥2 and the test suite covers integrity edge cases (0/1) and runtime for 2+ (including 3) inputs. Files: src/lib/op/math/LibOpMul.sol, test/src/lib/op/math/LibOpMul.t.sol, test/src/lib/op/math/uint256/LibOpUint256Mul.t.sol.

Comment thread src/lib/op/math/LibOpMul.sol

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
src/lib/op/math/LibOpMul.sol (1)

82-85: Unused lossless in reference; remove or assert.

Same nit as before: captured then no‑op. Either discard the second return or use it for a check.

Apply this diff to discard cleanly:

-            bool lossless;
-            (acc, lossless) = LibDecimalFloat.packLossy(signedCoefficient, exponent);
-            (lossless);
+            (acc,) = LibDecimalFloat.packLossy(signedCoefficient, exponent);

Alternatively, if you want reference to fail on quantization during tests:

-            bool lossless;
-            (acc, lossless) = LibDecimalFloat.packLossy(signedCoefficient, exponent);
-            (lossless);
+            bool lossless;
+            (acc, lossless) = LibDecimalFloat.packLossy(signedCoefficient, exponent);
+            assert(lossless);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3d0b8e6 and 3aa9671.

📒 Files selected for processing (1)
  • src/lib/op/math/LibOpMul.sol (4 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: rainix (ubuntu-latest, test-wasm-build)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-static)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-static)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-artifacts)
  • GitHub Check: rainix (macos-latest, rainix-rs-artifacts)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-artifacts)
  • GitHub Check: rainix (ubuntu-latest, rainix-rs-test)
  • GitHub Check: rainix (macos-latest, rainix-rs-test)
  • GitHub Check: rainix (ubuntu-latest, rainix-sol-test)
  • GitHub Check: git-clean
🔇 Additional comments (4)
src/lib/op/math/LibOpMul.sol (4)

15-16: Using directive is correct and necessary.

Enables .unpack() on Float. No issues.


46-48: Loop multiply per-operand is sound.

Unpack each operand and accumulate via implementation mul; unchecked { i++; } is appropriate.


74-74: Reference accumulator init LGTM.

Starting from inputs[0] as acc is consistent with the main path.


76-80: Reference multiply mirrors main logic correctly.

No discrepancies spotted between reference and main paths for the core mul.

Comment on lines +33 to +36
(int256 signedCoefficient, int256 exponent) = a.unpack();
(int256 signedCoefficientB, int256 exponentB) = b.unpack();
(signedCoefficient, exponent) =
LibDecimalFloatImplementation.mul(signedCoefficient, exponent, signedCoefficientB, exponentB);

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.

🧹 Nitpick

Unpack → impl.mul path looks correct.

Clean handoff to LibDecimalFloatImplementation.mul. Consider optional zero short‑circuit if result coefficient becomes 0 (still consuming remaining inputs but skipping extra unpacks/muls) for minor gas wins on sparse products.

Comment on lines +55 to +56
//slither-disable-next-line unused-return
(a,) = LibDecimalFloat.packLossy(signedCoefficient, exponent);

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.

🧹 Nitpick

Remove unnecessary Slither suppression.

You already capture the first return; the “unused-return” suppression is likely redundant here.

Apply this diff:

-        //slither-disable-next-line unused-return
         (a,) = LibDecimalFloat.packLossy(signedCoefficient, exponent);
📝 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
//slither-disable-next-line unused-return
(a,) = LibDecimalFloat.packLossy(signedCoefficient, exponent);
(a,) = LibDecimalFloat.packLossy(signedCoefficient, exponent);
🤖 Prompt for AI Agents
In src/lib/op/math/LibOpMul.sol around lines 55 to 56, the Slither suppression
comment "//slither-disable-next-line unused-return" is unnecessary because the
code already captures the first return value with "(a,)" from
LibDecimalFloat.packLossy; remove the suppression line so the file simply
performs the packed assignment without the redundant Slither directive.

@thedavidmeister
thedavidmeister merged commit c26b059 into main Sep 19, 2025
11 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

@coderabbitai assess this PR size classification for the totality of the PR with the following criterias and report it in your comment:

S/M/L PR Classification Guidelines:

This guide helps classify merged pull requests by effort and complexity rather than just line count. The goal is to assess the difficulty and scope of changes after they have been completed.

Small (S)

Characteristics:

  • Simple bug fixes, typos, or minor refactoring
  • Single-purpose changes affecting 1-2 files
  • Documentation updates
  • Configuration tweaks
  • Changes that require minimal context to review

Review Effort: Would have taken 5-10 minutes

Examples:

  • Fix typo in variable name
  • Update README with new instructions
  • Adjust configuration values
  • Simple one-line bug fixes
  • Import statement cleanup

Medium (M)

Characteristics:

  • Feature additions or enhancements
  • Refactoring that touches multiple files but maintains existing behavior
  • Breaking changes with backward compatibility
  • Changes requiring some domain knowledge to review

Review Effort: Would have taken 15-30 minutes

Examples:

  • Add new feature or component
  • Refactor common utility functions
  • Update dependencies with minor breaking changes
  • Add new component with tests
  • Performance optimizations
  • More complex bug fixes

Large (L)

Characteristics:

  • Major feature implementations
  • Breaking changes or API redesigns
  • Complex refactoring across multiple modules
  • New architectural patterns or significant design changes
  • Changes requiring deep context and multiple review rounds

Review Effort: Would have taken 45+ minutes

Examples:

  • Complete new feature with frontend/backend changes
  • Protocol upgrades or breaking changes
  • Major architectural refactoring
  • Framework or technology upgrades

Additional Factors to Consider

When deciding between sizes, also consider:

  • Test coverage impact: More comprehensive test changes lean toward larger classification
  • Risk level: Changes to critical systems bump up a size category
  • Team familiarity: Novel patterns or technologies increase complexity

Notes:

  • the assessment must be for the totality of the PR, that means comparing the base branch to the last commit of the PR
  • the assessment output must be exactly one of: S, M or L (single-line comment) in format of: SIZE={S/M/L}
  • do not include any additional text, only the size classification
  • your assessment comment must not include tips or additional sections
  • do NOT tag me or anyone else on your comment

@coderabbitai coderabbitai Bot mentioned this pull request Sep 19, 2025
4 tasks
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.

1 participant