Skip to content

Implement reversed and strictly positive ordered transform #7759

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 27, 2025

Conversation

velochy
Copy link
Contributor

@velochy velochy commented Apr 21, 2025

Description

Generalize Ordered transform to take two optional parameters:
positive: (default: False) also ensure values are positive. This has better geometry than chaining order with log-transform as it avoids double-exponentiation
ascending: (default: True) allow for both ascending and descending orders. Latter is achieved simply by reversing the vector in both forward and backward transforms.

This is motivated by a draft PR into pymc-extras where I need a default transform for a positive and descending-ordered RV (NormalSingularValue)

Related Issue

NA

Checklist

  • Checked that the pre-commit linting/style checks pass
  • Included tests that prove the fix is effective or that the new feature works
  • Added necessary documentation (docstrings and/or example notebooks)

Type of change

  • New feature / enhancement

Copy link

codecov bot commented Apr 21, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.83%. Comparing base (d34ed95) to head (97cdf4e).
Report is 1 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@           Coverage Diff           @@
##             main    #7759   +/-   ##
=======================================
  Coverage   92.83%   92.83%           
=======================================
  Files         107      107           
  Lines       18343    18354   +11     
=======================================
+ Hits        17028    17039   +11     
  Misses       1315     1315           
Files with missing lines Coverage Δ
pymc/distributions/transforms.py 98.59% <100.00%> (+0.11%) ⬆️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

@ricardoV94 ricardoV94 left a comment

Choose a reason for hiding this comment

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

Looks great, I left some small comments and request for testing

return pt.cumsum(x, axis=-1)
if self.positive:
x = pt.exp(value)
else: # Everything except the first element is positive
Copy link
Member

Choose a reason for hiding this comment

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

Comment is a but imprecise. The deltas are positive but the values may still be negative after the cumsum

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it to hopefully be more understandable

if self.positive:
x = pt.exp(value)
else: # Everything except the first element is positive
x = pt.zeros(value.shape)
Copy link
Member

@ricardoV94 ricardoV94 Apr 21, 2025

Choose a reason for hiding this comment

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

We should use empty, also below

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed. But just out of curiosity - how and why does it matter?

Copy link
Member

Choose a reason for hiding this comment

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

It's not a fix just an optimization. Theres was another use in the other method.

It's faster because the allocated array doesn't have to be filled with zeros.

@@ -281,6 +281,18 @@ def test_ordered():
vals = get_values(tr.ordered, Vector(R, 3), pt.vector, floatX(np.zeros(3)))
assert_array_equal(np.diff(vals) >= 0, True)

# Check that positive=True creates positive and still ordered values
Copy link
Member

@ricardoV94 ricardoV94 Apr 21, 2025

Choose a reason for hiding this comment

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

Do we have a test that checks that forward/backward are inverses + jacobian that we could parametrize with the new parameters?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added them. Had to adjust the check_jacobian_det to take the absolute value and to have an absolute tolerance along a relative one, because ascending=False permutes values and this leads to a negative determinant and a slightly less clean logdet computation in general as it can't just multiply the main diagonal.

@ricardoV94 ricardoV94 changed the title Generalize ordered transform Implement reversed and strictly positive ordered transform Apr 21, 2025
@velochy velochy force-pushed the generalize_odered_transform branch 2 times, most recently from 6f8be43 to dc594eb Compare April 21, 2025 17:11
Copy link
Member

@ricardoV94 ricardoV94 left a comment

Choose a reason for hiding this comment

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

Looks good, small typo

x = pt.empty(value.shape)
x = pt.set_subtensor(x[..., 0], value[..., 0])
x = pt.set_subtensor(x[..., 1:], pt.exp(value[..., 1:]))
x = pt.cumsum(x, axis=-1) # Add deltas cumulativelyto initial value
Copy link
Member

Choose a reason for hiding this comment

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

typo

@velochy velochy force-pushed the generalize_odered_transform branch from dc594eb to 87fd3a0 Compare April 21, 2025 18:28
@velochy velochy force-pushed the generalize_odered_transform branch from 87fd3a0 to 97cdf4e Compare April 23, 2025 08:03
@ricardoV94 ricardoV94 merged commit 1490141 into pymc-devs:main Apr 27, 2025
25 checks passed
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.

2 participants