Skip to content

Implement TdCondTdGridDistribution: conditional grid distribution on the hypertorus#1576

Open
Copilot wants to merge 15 commits intomainfrom
copilot/add-conditional-distribution-class
Open

Implement TdCondTdGridDistribution: conditional grid distribution on the hypertorus#1576
Copilot wants to merge 15 commits intomainfrom
copilot/add-conditional-distribution-class

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 31, 2026

  • Understand current code and sd_cond_sd_grid_distribution patterns
  • Rebase branch onto origin/main
  • Move td_cond_td_grid_distribution.py to pyrecest/distributions/conditional/
  • Harmonize TdCondTdGridDistribution with SdCondSdGridDistribution:
    • Use pyrecest backend imports throughout (no raw numpy in class methods)
    • Remove @beartype decorators
    • Remove n_grid_points_per_dim complexity
    • Add multiply() method
    • normalize() returns self without calling _check_normalization()
    • Change RuntimeWarning to UserWarning
    • fix_dim uses linalg.norm + argmin
    • marginalize_out uses backend sum()
    • from_function parameter renamed to no_of_grid_points
    • Imports of HypertoroidalGridDistribution moved inside methods (circular import avoidance)
  • Update conditional/init.py to export TdCondTdGridDistribution
  • Update test file (new import path, UserWarning, added multiply/invalid tests, removed stale grid_type roundtrip assertion)
  • All 19 tests pass

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/7d751a84-d968-4c42-864e-1b8382d38b4d

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

github-actions bot commented Mar 31, 2026

MegaLinter analysis: Error

Descriptor Linter Files Fixed Errors Warnings Elapsed time
✅ COPYPASTE jscpd yes no no 8.47s
✅ JSON prettier 2 0 0 0 0.44s
✅ JSON v8r 2 0 0 2.28s
✅ MARKDOWN markdownlint 1 0 0 0 0.68s
✅ MARKDOWN markdown-table-formatter 1 0 0 0 0.25s
✅ PYTHON bandit 251 0 0 3.11s
✅ PYTHON black 251 2 0 0 4.53s
✅ PYTHON flake8 251 0 0 1.74s
✅ PYTHON isort 251 2 0 0 0.48s
✅ PYTHON mypy 251 0 0 3.98s
❌ PYTHON pylint 251 5 0 70.34s
✅ PYTHON ruff 251 2 0 0 0.04s
✅ REPOSITORY checkov yes no no 21.54s
✅ REPOSITORY gitleaks yes no no 4.47s
✅ REPOSITORY git_diff yes no no 0.04s
✅ REPOSITORY secretlint yes no no 6.07s
✅ REPOSITORY syft yes no no 3.84s
✅ REPOSITORY trivy-sbom yes no no 1.73s
✅ REPOSITORY trufflehog yes no no 17.46s
✅ YAML prettier 4 0 0 0 0.47s
✅ YAML v8r 4 0 0 5.14s
✅ YAML yamllint 4 0 0 0.44s

Detailed Issues

❌ PYTHON / pylint - 5 errors
************* Module update_init_helper
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.distributions.conditional.sd_cond_sd_grid_distribution:[104:170]
==pyrecest.distributions.conditional.td_cond_td_grid_distribution:[93:159]
                "Check input or increase tolerance. "
                "No normalisation is performed; you may want to do this manually.",
                UserWarning,
            )

    def normalize(self):
        """No-op – returns ``self`` for compatibility."""
        return self

    # ------------------------------------------------------------------
    # Arithmetic
    # ------------------------------------------------------------------

    def multiply(self, other):
        """
        Element-wise multiply two conditional grid distributions.

        The resulting distribution is *not* normalized.

        Parameters
        ----------
        other : SdCondSdGridDistribution
            Must be defined on the same grid.

        Returns
        -------
        SdCondSdGridDistribution
        """
        if not array_equal(self.grid, other.grid):
            raise ValueError(
                "Multiply:IncompatibleGrid: Can only multiply distributions "
                "defined on identical grids."
            )
        warnings.warn(
            "Multiply:UnnormalizedResult: Multiplication does not yield a "
            "normalized result.",
            UserWarning,
        )
        result = copy.deepcopy(self)
        result.grid_values = result.grid_values * other.grid_values
        return result

    # ------------------------------------------------------------------
    # Marginalisation and conditioning
    # ------------------------------------------------------------------

    def marginalize_out(self, first_or_second):
        """
        Marginalize out one of the two spheres.

        Parameters
        ----------
        first_or_second : int  (1 or 2)
            ``1`` marginalizes out the *first* dimension (sums over rows);
            ``2`` marginalizes out the *second* dimension (sums over columns).

        Returns
        -------
        HypersphericalGridDistribution
        """
        # Import here to avoid circular imports
        from pyrecest.distributions.hypersphere_subset.hyperspherical_grid_distribution import (  # pylint: disable=import-outside-toplevel
            HypersphericalGridDistribution,
        )

        if first_or_second == 1: (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.distributions.conditional.sd_cond_sd_grid_distribution:[280:298]
==pyrecest.distributions.conditional.td_cond_td_grid_distribution:[279:296]
        if fun_does_cartesian_product:
            fvals = fun(grid, grid)
            grid_values = fvals.reshape(n, n)
        else:
            # Build index pairs: idx_a[i, j] = i, idx_b[i, j] = j
            idx_a, idx_b = meshgrid(arange(n), arange(n), indexing="ij")
            grid_a = grid[idx_a.ravel()]  # (n*n, d)
            grid_b = grid[idx_b.ravel()]  # (n*n, d)
            fvals = fun(grid_a, grid_b)  # (n*n,)

            if fvals.shape == (n**2, n**2):
                raise ValueError(
                    "Function apparently performs the Cartesian product itself. "
                    "Set fun_does_cartesian_product=True."
                )

            grid_values = fvals.reshape(n, n)
 (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.distributions.conditional.sd_cond_sd_grid_distribution:[210:223]
==pyrecest.distributions.conditional.td_cond_td_grid_distribution:[199:212]
        locb = argmin(diffs)
        if diffs[locb] > 1e-10:
            raise ValueError(
                "Cannot fix value at this point because it is not on the grid."
            )

        if first_or_second == 1:
            grid_values_slice = self.grid_values[locb, :]
        elif first_or_second == 2:
            grid_values_slice = self.grid_values[:, locb]
        else:
            raise ValueError("first_or_second must be 1 or 2.")
 (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.distributions.conditional.sd_cond_sd_grid_distribution:[65:85]
==pyrecest.distributions.conditional.td_cond_td_grid_distribution:[57:77]
            )

        if enforce_pdf_nonnegative and any(grid_values < 0):
            raise ValueError("grid_values must be non-negative.")

        self.grid = grid
        self.grid_values = grid_values
        self.enforce_pdf_nonnegative = enforce_pdf_nonnegative
        # Embedding dimension of the Cartesian product space (convention from
        # libDirectional: dim = 2 * dim_of_individual_torus).
        self.dim = 2 * d

        self._check_normalization()

    # ------------------------------------------------------------------
    # Normalization
    # ------------------------------------------------------------------

    def _check_normalization(self, tol=0.01):
        """Warn if any column is not normalized to 1 over the torus.""" (duplicate-code)
update_init_helper.py:1:0: R0801: Similar lines in 2 files
==pyrecest.distributions.conditional.sd_cond_sd_grid_distribution:[52:62]
==pyrecest.distributions.conditional.td_cond_td_grid_distribution:[49:59]
        if grid.ndim != 2:
            raise ValueError("grid must be a 2D array of shape (n_points, d).")

        n_points, d = grid.shape

        if grid_values.ndim != 2 or grid_values.shape != (n_points, n_points):
            raise ValueError(
                f"grid_values must be a square 2D array of shape ({n_points}, {n_points})."
            )
 (duplicate-code)

------------------------------------
Your code has been rated at 10.00/10

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?

…ected-access

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/0221331a-f5da-4059-aae5-86498d14a29d

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

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 commit 42352bc. The MegaLinter errors were:

  • W0611 / F401 (unused imports): removed meshgrid from the main module and warnings/pi from the test file
  • R0914 (too many local variables in from_function): collapsed intermediate index variables (r, idx_i_np, idx_j_np, fvals_flat) — count dropped from 17 → 13
  • W0212 (protected-access to _n_grid_points_per_dim): moved it to an optional __init__ parameter so from_function passes it directly at construction instead of setting it after the fact

@github-actions
Copy link
Copy Markdown

github-actions bot commented Mar 31, 2026

Test Results

0 files   -    12  0 suites   - 12   0s ⏱️ - 3h 6m 13s
0 tests  -   533  0 ✅  -   533  0 💤 ±    0  0 ❌ ±0 
0 runs   - 6 608  0 ✅  - 5 432  0 💤  - 1 176  0 ❌ ±0 

Results for commit 5d64c77. ± Comparison against base commit f5c0f75.

♻️ This comment has been updated with latest results.

@FlorianPfaff
Copy link
Copy Markdown
Owner

@copilot Can you rebase onto main and adapt and harmonize your code with sd_cond_sd_grid_distribution?

FlorianPfaff and others added 9 commits March 31, 2026 16:52
Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
…ty polygon dimension, and @classmethod on setUp

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/27f787c9-722d-4cc0-93e6-0ff0f3f8e4f6

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/1c6bef08-40d1-4a9d-9810-72aeaceca573

Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
…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>
Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
Co-authored-by: FlorianPfaff <6773539+FlorianPfaff@users.noreply.github.com>
…d_distribution

Agent-Logs-Url: https://github.com/FlorianPfaff/PyRecEst/sessions/22e786eb-4283-4775-aa01-958e68d20267

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

Head branch was pushed to by a user without write access

@FlorianPfaff FlorianPfaff enabled auto-merge March 31, 2026 19:08
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