Repository: scipy/scipy
File: scipy/stats/_continuous_distns.py (Python)

Code before:
        ab_term = c**(n+1)
        dc_term = _lazyselect(
            [d == 0.0, (0.0 < d) & (d < 1.0), d == 1.0],
            [lambda d: 1.0,
             lambda d: np.expm1((n+2) * np.log(d)) / (d-1.0),
             lambda d: n+2],
            [d])
        val = 2.0 / (1.0+d-c) * (dc_term - ab_term) / ((n+1) * (n+2))
        return val

    def _entropy(self, c, d):
        # Using the parameterization from Wikipedia (van Dorp, 2003)
        # with a=bottom left, c=top left, d=top right, b=bottom right
        # gives a'=loc, b'=loc+c*scale, c'=loc+d*scale, d'=loc+scale,
        # which for loc=0, scale=1 is a'=0, b'=c, c'=d, d'=1.
        # Substituting into the entropy formula from Wikipedia gives
        # the following result.
        return 0.5 * (1.0-d+c) / (1.0+d-c) + np.log(0.5 * (1.0+d-c))

    def _fitstart(self, data):
        """Override _fitstart to provide sensible default starting values for c and d.
        
        The default starting values c=0.33, d=0.66 provide better convergence
        than the generic defaults, especially for trapezoidal distributions
        that are not close to triangular.
        """
        return super()._fitstart(data, args=(0.33, 0.66))


trapezoid = trapezoid_gen(a=0.0, b=1.0, name="trapezoid")


class triang_gen(rv_continuous):
    r"""A triangular continuous random variable.

    %(before_notes)s

    Notes
    -----
    The triangular distribution can be represented with an up-sloping line from
    ``loc`` to ``(loc + c*scale)`` and then downsloping for ``(loc + c*scale)``
    to ``(loc + scale)``.

    `triang` takes ``c`` as a shape parameter for :math:`0 \le c \le 1`.

    %(after_notes)s

    The standard form is in the range [0, 1] with c the mode.
    The location parameter shifts the start to `loc`.
    The scale parameter changes the width from 1 to `scale`.


Review comment (bug):
This docstring isn't correct. The problem is not only with non-triangular data, but with any data, because the points in the initial simplex become c=1.05 and d=1.05., which are not valid parameters to the triangular distribution.

Additionally, I would suggest a shorter comment. The reason I would suggest that is that the comment's length should be proportional to how complex / hairy the associated code is. Proposed wording:

```suggestion
        # Arbitrary, but c=d=1 fails due to being on edge of bounds
```

Code after:
        ab_term = c**(n+1)
        dc_term = _lazyselect(
            [d == 0.0, (0.0 < d) & (d < 1.0), d == 1.0],
            [lambda d: 1.0,
             lambda d: np.expm1((n+2) * np.log(d)) / (d-1.0),
             lambda d: n+2],
            [d])
        val = 2.0 / (1.0+d-c) * (dc_term - ab_term) / ((n+1) * (n+2))
        return val

    def _entropy(self, c, d):
        # Using the parameterization from Wikipedia (van Dorp, 2003)
        # with a=bottom left, c=top left, d=top right, b=bottom right
        # gives a'=loc, b'=loc+c*scale, c'=loc+d*scale, d'=loc+scale,
        # which for loc=0, scale=1 is a'=0, b'=c, c'=d, d'=1.
        # Substituting into the entropy formula from Wikipedia gives
        # the following result.
        return 0.5 * (1.0-d+c) / (1.0+d-c) + np.log(0.5 * (1.0+d-c))

    def _fitstart(self, data, args=None):
        # Arbitrary, but c=d=1 fails due to being on edge of bounds
        if args is None:
            args = (0.33, 0.66)
        return super()._fitstart(data, args=args)


trapezoid = trapezoid_gen(a=0.0, b=1.0, name="trapezoid")


class triang_gen(rv_continuous):
    r"""A triangular continuous random variable.

    %(before_notes)s

    Notes
    -----
    The triangular distribution can be represented with an up-sloping line from
    ``loc`` to ``(loc + c*scale)`` and then downsloping for ``(loc + c*scale)``
    to ``(loc + scale)``.

    `triang` takes ``c`` as a shape parameter for :math:`0 \le c \le 1`.

    %(after_notes)s

    The standard form is in the range [0, 1] with c the mode.
    The location parameter shifts the start to `loc`.
    The scale parameter changes the width from 1 to `scale`.

    %(example)s

    """