Skip to content

Implement SdCondSdGridDistribution for PyRecEst#1575

Merged
FlorianPfaff merged 2 commits intomainfrom
copilot/add-conditional-distribution-grid
Mar 31, 2026
Merged

Implement SdCondSdGridDistribution for PyRecEst#1575
FlorianPfaff merged 2 commits intomainfrom
copilot/add-conditional-distribution-grid

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

Ports the MATLAB SdCondSdGridDistribution class from libDirectional to Python. Represents a conditional distribution f(a|b) on Sd × Sd as a grid of values, where grid_values[i, j] = f(grid[i] | grid[j]).

Conventions

  • grid: (n_points, d) — embedding-dimension coordinates (d=3 for S²)
  • grid_values: (n_points, n_points) — conditional pdf values
  • dim = 2 * d — Cartesian-product embedding dimension (libDirectional convention)

New class: SdCondSdGridDistribution

  • __init__ — validates inputs; warns/raises if column-wise normalization check fails. Fixes a latent bug in the MATLAB original where the "maybe wrong order" branch could never trigger.
  • normalize() — no-op returning self (matches MATLAB behavior).
  • multiply(other) — element-wise grid multiplication with grid-compatibility guard.
  • marginalize_out(1|2) — sums over rows or columns, returns a HypersphericalGridDistribution.
  • fix_dim(1|2, point) — conditions on an existing grid point, returns a HypersphericalGridDistribution.
  • from_function(fun, n, ...) — static factory supporting both a flat paired-call convention and a caller-side Cartesian-product convention.
from pyrecest.distributions.conditional import SdCondSdGridDistribution
import numpy as np

surface = 4 * np.pi  # S² surface area
def vmf_like(a, b):
    # a, b: (n_pairs, 3) — evaluate f(a|b) for each pair
    return np.exp(2.0 * np.sum(a * b, axis=1)) / surface

sc = SdCondSdGridDistribution.from_function(vmf_like, no_of_grid_points=100, dim=6)
# Fix the second argument at the first grid point
cond = sc.fix_dim(2, sc.grid[0])   # → HypersphericalGridDistribution
marg = sc.marginalize_out(1)        # → HypersphericalGridDistribution

Notes

  • The get_grid_hypersphere import is deferred inside from_function to avoid a circular-import path through pyrecest.sampling.
  • dim argument to from_function follows the Cartesian-product embedding convention (6 for S²×S²); internally converted to manifold dim via dim // 2 - 1.

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/1c6bef08-40d1-4a9d-9810-72aeaceca573

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Mar 31, 2026

MegaLinter analysis: Success

Descriptor Linter Files Fixed Errors Warnings Elapsed time
✅ COPYPASTE jscpd yes no no 7.74s
✅ JSON prettier 2 0 0 0 0.45s
✅ JSON v8r 2 0 0 2.56s
✅ MARKDOWN markdownlint 1 0 0 0 0.65s
✅ MARKDOWN markdown-table-formatter 1 0 0 0 0.27s
✅ PYTHON bandit 249 0 0 3.16s
✅ PYTHON black 249 1 0 0 4.39s
✅ PYTHON flake8 249 0 0 1.71s
✅ PYTHON isort 249 4 0 0 0.48s
✅ PYTHON mypy 249 0 0 4.19s
✅ PYTHON pylint 249 0 0 70.57s
✅ PYTHON ruff 249 4 0 0 0.05s
✅ REPOSITORY checkov yes no no 22.48s
✅ REPOSITORY gitleaks yes no no 4.33s
✅ REPOSITORY git_diff yes no no 0.04s
✅ REPOSITORY secretlint yes no no 5.57s
✅ REPOSITORY syft yes no no 3.56s
✅ REPOSITORY trivy-sbom yes no no 1.7s
✅ REPOSITORY trufflehog yes no no 15.94s
✅ YAML prettier 4 0 0 0 0.46s
✅ YAML v8r 4 0 0 4.83s
✅ YAML yamllint 4 0 0 0.48s

See detailed reports in MegaLinter artifacts

Your project could benefit from a custom flavor, which would allow you to run only the linters you need, and thus improve runtime performances. (Skip this info by defining FLAVOR_SUGGESTIONS: false)

  • Documentation: Custom Flavors
  • Command: npx mega-linter-runner@9.4.0 --custom-flavor-setup --custom-flavor-linters PYTHON_PYLINT,PYTHON_BLACK,PYTHON_FLAKE8,PYTHON_ISORT,PYTHON_BANDIT,PYTHON_MYPY,PYTHON_RUFF,COPYPASTE_JSCPD,JSON_V8R,JSON_PRETTIER,MARKDOWN_MARKDOWNLINT,MARKDOWN_MARKDOWN_TABLE_FORMATTER,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,REPOSITORY_GITLEAKS,REPOSITORY_SECRETLINT,REPOSITORY_SYFT,REPOSITORY_TRIVY_SBOM,REPOSITORY_TRUFFLEHOG,YAML_PRETTIER,YAML_YAMLLINT,YAML_V8R

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

@FlorianPfaff
Copy link
Copy Markdown
Owner

@copilot Can you fix the linter errors by megalinter?

…nts, add __all__

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/d724643e-1252-4c50-b114-57aac876ac0f

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
auto-merge was automatically disabled March 31, 2026 12:59

Head branch was pushed to by a user without write access

Copy link
Copy Markdown
Contributor Author

Copilot AI commented Mar 31, 2026

@copilot Can you fix the linter errors by megalinter?

Fixed in 2efa63c. The MegaLinter failures were:

  • pylint E1101 (no-member on pyrecest.backend.__backend_name__): added # pylint: disable=no-member to each occurrence, matching the pattern used in all other test files.
  • pylint W0404 (reimported): removed the local from pyrecest.backend import ones as be_ones inside three test methods; they now use the top-level ones import.
  • pylint W0611 / flake8 F401 (unused import): removed the unused zeros import from the test file.
  • flake8/ruff F401 (imported but unused in conditional/__init__.py): added __all__ = ["SdCondSdGridDistribution"] to mark the re-export as intentional.

Copilot AI requested a review from FlorianPfaff March 31, 2026 13:00
@FlorianPfaff FlorianPfaff enabled auto-merge March 31, 2026 13:11
@FlorianPfaff FlorianPfaff merged commit 7fc5092 into main Mar 31, 2026
18 checks passed
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