Skip to content

[torchlib] Implement fmax, fmin and hypot - #3169

Open
Shawn (ShawnNotFound) wants to merge 4 commits into
microsoft:mainfrom
ShawnNotFound:torchlib-fmax-fmin-hypot
Open

Shawn (ShawnNotFound) wants to merge 4 commits into
microsoft:mainfrom
ShawnNotFound:torchlib-fmax-fmin-hypot

Conversation

@ShawnNotFound

Copy link
Copy Markdown

torch.fmax, torch.fmin and torch.hypot currently fail to export:

class Model(torch.nn.Module):
    def forward(self, a, b):
        return torch.fmax(a, b)

torch.onnx.export(Model(), (torch.randn(3), torch.randn(3)), dynamo=True)
# DispatchError: No ONNX function found for <OpOverload(op='prims.fmax', overload='default')>

This implements them and registers them for both the aten and prims overloads, like aten_remainder does.

  • fmax / fmin: Max and Min return NaN when either input is NaN, but fmax and fmin return the other value and only give NaN when both inputs are NaN. For floating point inputs the NaN positions are filled from the other input. Bool inputs use Or / And as in aten_maximum / aten_minimum.
  • hypot: computing sqrt(x*x + y*y) directly overflows or underflows well before the result does, e.g. hypot(300, 400) in float16. It's computed as big * sqrt(1 + (small / big)**2) instead, with zeros and infinities handled separately so that it matches torch.hypot, including hypot(inf, nan) == inf. I used Abs(x) == inf rather than IsInf, since IsInf only accepts float16 from opset 20.

Tests: OpInfo entries for the three ops, and e2e tests for NaN inputs, integer inputs and hypot inputs whose squares overflow or underflow. Against PyTorch on random inputs over a wide range, hypot is within 2 ulp for float32 and float64 and 1 ulp for float16.

Max and Min return NaN when either input is NaN, so for floating point
inputs the other value is selected where one input is NaN. Both ops are
also registered for the prims overloads, which is what torch.export
produces for torch.fmax and torch.fmin.
Squaring the inputs overflows or underflows well before the result does,
e.g. hypot(300, 400) in float16, so the larger magnitude is factored out
first. Zero and infinite inputs are handled separately so that the
results match torch.hypot, including hypot(inf, nan) == inf.
@justinchuby
Justin Chu (justinchuby) requested a balanced review from Copilot November 6, 2026 18:20
@justinchuby Justin Chu (justinchuby) added the module: torchlib Related to the torch/aten function lib in development label Nov 6, 2026

@justinchuby Justin Chu (justinchuby) left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks!

@codecov

codecov Bot commented Nov 6, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.39%. Comparing base (5b210da) to head (6e44eea).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3169      +/-   ##
==========================================
+ Coverage   73.34%   73.39%   +0.04%     
==========================================
  Files         269      269              
  Lines       33564    33597      +33     
  Branches     3210     3215       +5     
==========================================
+ Hits        24618    24657      +39     
+ Misses       7876     7870       -6     
  Partials     1070     1070              

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

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.

🟡 Changes recommended

The float16 hypot calculation can overflow to infinity when the expected result is finite, requiring float32 intermediates and a boundary-case regression test.

1 open issue
What changed in this PR

Adds TorchLib export support for torch.fmax, torch.fmin, and torch.hypot, registered for both ATen and prims overloads.

Changes:

  • Implements NaN-aware fmax and fmin, including boolean handling.
  • Implements scaled hypot computation with zero and infinity handling.
  • Adds OpInfo coverage and end-to-end tests for special values, integer inputs, and numerical range.
File Description
tests/​function_libs/​torch_lib/​ops_test_data.py Registers OpInfo tests for all three operators.
tests/​function_libs/​torch_lib/​e2e_ops_tests.py Adds export tests for edge cases and numerical range.
onnxscript/​function_libs/​torch_lib/​ops/​core.py Implements and registers the three operators.

Review effort: Balanced

Shawn (ShawnNotFound) and others added 2 commits November 6, 2026 18:32
Doing the scaling in float32 keeps the intermediate steps in full
precision for results near the top of the half precision range. It also
makes bfloat16 work on onnxruntime, which has no bfloat16 kernel for Abs.
@justinchuby
Justin Chu (justinchuby) enabled auto-merge (squash) November 6, 2026 22:36

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

module: torchlib Related to the torch/aten function lib in development

Projects

Development

Successfully merging this pull request may close these issues.

3 participants