jiahuimbzuai/CoQuIR huggingface dataset:
//  [python]
def get_avg_reward(reward, contexts, round=False):
    # Computes the average/integral reward
    if reward.size != contexts.size:
        if contexts.shape[1:] in [(4000, 5), (8000, 5)]: # Hard code for a particular scenario, to ensure it works correctly.
            contexts = contexts[:, :, :2]
            AA =  np.mean(reward, axis=-1)
            return AA
        alls = []
        for seed in range(len(reward)):
            assert contexts.shape[-1] == 2
            C = contexts[seed]
            Ys = C[:, 1]
            Rs = reward[seed]

            updated_integral = []
            updated_y        = []
            for y in np.unique(Ys):
                idx = Ys == y
                
                tmp_x_val = C[idx, 0]
                tmp_r     = (Rs[idx])
                if len(tmp_x_val) == 1: 
                    a = tmp_r[0]
                else:
                    a = s.integrate.simpson(tmp_r, tmp_x_val) / (np.max(tmp_x_val) - np.min(tmp_x_val))
                updated_integral.append(a)
                updated_y.append(y)
            if len(updated_integral) == 1:
                new_val = updated_integral[0]
            else:
                new_val = s.integrate.simpson(updated_integral, updated_y) / (np.max(updated_y) - np.min(updated_y))
            alls.append(new_val)
        alls = np.array(alls)
        if round: alls = np.round(alls)
        return alls
        
    R = reward.reshape(reward.shape)
    C = contexts.reshape(reward.shape)
    a = s.integrate.simpson(R, C) / (np.max(contexts) - np.min(contexts))
    if round: a = np.round(a)
    return a
//  [python]
def get_avg_reward(reward, contexts, round=False):
    # Computes the average/integral reward
    if reward.size != contexts.size:
        if contexts.shape[1:] in [(4000, 5), (8000, 5)]: # Hard code for a particular scenario, to ensure it works correctly.
            contexts = contexts[:, :, :2]
            AA =  np.mean(reward, axis=-1)
            return AA
        alls = []
        for seed in range(len(reward)):
            assert contexts.shape[-1] == 2
            C = contexts[seed]
            Ys = C[:, 1]
            Rs = reward[seed]

            updated_integral = []
            updated_y        = []
            for y in np.unique(Ys):
                idx = Ys == y
                
                tmp_x_val = C[idx, 0]
                tmp_r     = (Rs[idx])
                if len(tmp_x_val) == 1: 
                    a = tmp_r[0]
                else:
                    a = integrate.simpson(tmp_r, tmp_x_val) / (np.max(tmp_x_val) - np.min(tmp_x_val))
                updated_integral.append(a)
                updated_y.append(y)
            if len(updated_integral) == 1:
                new_val = updated_integral[0]
            else:
                new_val = integrate.simpson(updated_integral, updated_y) / (np.max(updated_y) - np.min(updated_y))
            alls.append(new_val)
        alls = np.array(alls)
        if round: alls = np.round(alls)
        return alls
        
    R = reward.reshape(reward.shape)
    C = contexts.reshape(reward.shape)
    a = integrate.simpson(R, C) / (np.max(contexts) - np.min(contexts))
    if round: a = np.round(a)
    return a
//  [python]
def __init__(
        self,
        data: FDataGrid,
        label: str,
        integration_weights: Optional[np.ndarray],  # type: ignore[type-arg]
        regularization: Optional[L2Regularization[Any]],
    ) -> None:
        """Initialize the data of a grid block."""
        self.label = label

        self.mean = data.mean()
        self.data = data - self.mean
        self.data_matrix = data.data_matrix[..., 0]

        # Arrange the integration weights in a diagonal matrix
        # By default, use Simpson's rule
        if integration_weights is None:
            identity = np.identity(self.data_matrix.shape[1])
            integration_weights = scipy.integrate.simps(
                identity,
                x=self.data.grid_points[0],
            )
        self.integration_weights = np.diag(integration_weights)

        # Compute the regularization matrix
        # By default, all zeros (no regularization)
        regularization_matrix = None
        if regularization is not None:
            regularization_matrix = compute_penalty_matrix(
                basis_iterable=(
                    _GridBasis(grid_points=self.data.grid_points),
                ),
                regularization_parameter=1,
                regularization=regularization,
            )
        if regularization_matrix is None:
            regularization_matrix = np.zeros(
                (self.data_matrix.shape[1], self.data_matrix.shape[1]),
            )

        self.regularization_matrix = regularization_matrix
        self.G_data_weights = self.integration_weights
        self.G_weights = self.integration_weights
//  [python]
def __init__(
        self,
        data: FDataGrid,
        label: str,
        integration_weights: Optional[np.ndarray],  # type: ignore[type-arg]
        regularization: Optional[L2Regularization[Any]],
    ) -> None:
        """Initialize the data of a grid block."""
        self.label = label

        self.mean = data.mean()
        self.data = data - self.mean
        self.data_matrix = data.data_matrix[..., 0]

        # Arrange the integration weights in a diagonal matrix
        # By default, use Simpson's rule
        if integration_weights is None:
            identity = np.identity(self.data_matrix.shape[1])
            integration_weights = scipy.integrate.simpson(
                identity,
                x=self.data.grid_points[0],
            )
        self.integration_weights = np.diag(integration_weights)

        # Compute the regularization matrix
        # By default, all zeros (no regularization)
        regularization_matrix = None
        if regularization is not None:
            regularization_matrix = compute_penalty_matrix(
                basis_iterable=(
                    _GridBasis(grid_points=self.data.grid_points),
                ),
                regularization_parameter=1,
                regularization=regularization,
            )
        if regularization_matrix is None:
            regularization_matrix = np.zeros(
                (self.data_matrix.shape[1], self.data_matrix.shape[1]),
            )

        self.regularization_matrix = regularization_matrix
        self.G_data_weights = self.integration_weights
        self.G_weights = self.integration_weights
//  [python]
def test_basis_vs_grid(self) -> None:
        """Test that the results are the same in basis and grid."""
        X, y = fetch_tecator(
            return_X_y=True,
        )

        original_grid_points = X.grid_points[0]
        # Express the data in a FDataBasis
        X = X.to_basis(BSplineBasis(n_basis=20))

        # Fit the model
        fplsr = FPLSRegression[FData, NDArrayFloat](n_components=5)
        fplsr.fit(X, y)
        basis_components = fplsr.fpls_.x_rotations_(original_grid_points)

        # Go back to grid
        new_grid_points = np.linspace(
            original_grid_points[0],
            original_grid_points[-1],
            1000,
        )
        X = X.to_grid(grid_points=new_grid_points)

        # Get the weights for the Simpson's rule
        identity = np.eye(len(X.grid_points[0]))
        ss_weights = scipy.integrate.simps(identity, x=X.grid_points[0])

        # Fit the model with weights
        fplsr = FPLSRegression(
            n_components=5,
            _integration_weights_X=ss_weights,
        )
        fplsr.fit(X, y)

        grid_components = fplsr.fpls_.x_rotations_(original_grid_points)

        np.testing.assert_allclose(
            basis_components,
            grid_components,
            rtol=3e-3,
        )
//  [python]
def test_basis_vs_grid(self) -> None:
        """Test that the results are the same in basis and grid."""
        X, y = fetch_tecator(
            return_X_y=True,
        )

        original_grid_points = X.grid_points[0]
        # Express the data in a FDataBasis
        X = X.to_basis(BSplineBasis(n_basis=20))

        # Fit the model
        fplsr = FPLSRegression[FData, NDArrayFloat](n_components=5)
        fplsr.fit(X, y)
        basis_components = fplsr.fpls_.x_rotations_(original_grid_points)

        # Go back to grid
        new_grid_points = np.linspace(
            original_grid_points[0],
            original_grid_points[-1],
            1000,
        )
        X = X.to_grid(grid_points=new_grid_points)

        # Get the weights for the Simpson's rule
        identity = np.eye(len(X.grid_points[0]))
        ss_weights = scipy.integrate.simpson(identity, x=X.grid_points[0])

        # Fit the model with weights
        fplsr = FPLSRegression(
            n_components=5,
            _integration_weights_X=ss_weights,
        )
        fplsr.fit(X, y)

        grid_components = fplsr.fpls_.x_rotations_(original_grid_points)

        np.testing.assert_allclose(
            basis_components,
            grid_components,
            rtol=3e-3,
        )
//  [python]
def integrate_simpson(self, axis, out=None, rechunk=False):
        """Calculate the integral of a Signal along an axis using
        `Simpson's rule <https://en.wikipedia.org/wiki/Simpson%%27s_rule>`_.

        Parameters
        ----------
        axis %s
        %s
        %s

        Returns
        -------
        s : :class:`~hyperspy.signal.BaseSignal` (or subclass)
            A new Signal containing the integral of the provided Signal along
            the specified axis.

        See Also
        --------
        hyperspy.api.signals.BaseSignal.derivative,
        hyperspy.api.signals.BaseSignal.integrate1D

        Examples
        --------
        >>> s = BaseSignal(np.random.random((64, 64, 1024)))
        >>> s
        <BaseSignal, title: , dimensions: (|1024, 64, 64)>
        >>> s.integrate_simpson(0)
        <Signal2D, title: , dimensions: (|64, 64)>

        """
        axis = self.axes_manager[axis]
        s = out or self._deepcopy_with_new_data(None)
        data = s.simpson(y=self.data, x=axis.axis, axis=axis.index_in_array)
        if out is not None:
            out.data[:] = data
            out.events.data_changed.trigger(obj=out)
        else:
            s.data = data
            s._remove_axis(axis.index_in_axes_manager)
            return s
//  [python]
def integrate_simpson(self, axis, out=None, rechunk=False):
        """Calculate the integral of a Signal along an axis using
        `Simpson's rule <https://en.wikipedia.org/wiki/Simpson%%27s_rule>`_.

        Parameters
        ----------
        axis %s
        %s
        %s

        Returns
        -------
        s : :class:`~hyperspy.signal.BaseSignal` (or subclass)
            A new Signal containing the integral of the provided Signal along
            the specified axis.

        See Also
        --------
        hyperspy.api.signals.BaseSignal.derivative,
        hyperspy.api.signals.BaseSignal.integrate1D

        Examples
        --------
        >>> s = BaseSignal(np.random.random((64, 64, 1024)))
        >>> s
        <BaseSignal, title: , dimensions: (|1024, 64, 64)>
        >>> s.integrate_simpson(0)
        <Signal2D, title: , dimensions: (|64, 64)>

        """
        axis = self.axes_manager[axis]
        s = out or self._deepcopy_with_new_data(None)
        data = integrate.simpson(y=self.data, x=axis.axis, axis=axis.index_in_array)
        if out is not None:
            out.data[:] = data
            out.events.data_changed.trigger(obj=out)
        else:
            s.data = data
            s._remove_axis(axis.index_in_axes_manager)
            return s
//  [python]
def _pairwise_fem_inner_product(
    basis_fd: FData,
    fd: FData,
    y_val: float,
    grid: NDArrayFloat,
) -> NDArrayFloat:

    eval_grid_fem = np.concatenate(
        (
            grid[:, None],
            np.full(
                shape=(len(grid), 1),
                fill_value=y_val,
            ),
        ),
        axis=1,
    )

    eval_fem = basis_fd(eval_grid_fem)
    eval_fd = fd(grid)

    prod = eval_fem * eval_fd
    integral = scipy.integrate.simps(prod, x=grid, axis=1)
    return np.sum(integral, axis=-1)
//  [python]
def _pairwise_fem_inner_product(
    basis_fd: FData,
    fd: FData,
    y_val: float,
    grid: NDArrayFloat,
) -> NDArrayFloat:

    eval_grid_fem = np.concatenate(
        (
            grid[:, None],
            np.full(
                shape=(len(grid), 1),
                fill_value=y_val,
            ),
        ),
        axis=1,
    )

    eval_fem = basis_fd(eval_grid_fem)
    eval_fd = fd(grid)

    prod = eval_fem * eval_fd
    integral = scipy.integrate.simpson(prod, x=grid, axis=1)
    return np.sum(integral, axis=-1)
//  [python]
def cdf_from_characteristic(
        self,
        n: int | None = None,
        *,
        frequency_n: int | None = None,
        simpson_rule: bool = True,
        **kwargs: Any,
    ) -> TransformResult:
        n = n or 10
        transform = self.get_transform(frequency_n, self.support, **kwargs)
        frequency = transform.frequency_domain
        c = self.characteristic(frequency)
        a = 1 / np.pi
        result = []
        x = np.arange(n or 10)
        for m in x:
            d = np.sin(0.5 * frequency)
            d[0] = 1.0
            f = (
                np.sin(0.5 * (m + 1) * frequency)
                * (c * np.exp(-0.5 * Im * m * frequency)).real
                / d
            )
            f[0] = c[0].real  # type: ignore[index]
            if simpson_rule:
                result.append(a * s(f, x=frequency))
            else:
                result.append(a * np.trapz(f, frequency))
        pdf = np.maximum(np.diff(result, prepend=0), 0)
        return TransformResult(x=x, y=np.cumsum(pdf))
//  [python]
def cdf_from_characteristic(
        self,
        n: int | None = None,
        *,
        frequency_n: int | None = None,
        simpson_rule: bool = True,
        **kwargs: Any,
    ) -> TransformResult:
        n = n or 10
        transform = self.get_transform(frequency_n, self.support, **kwargs)
        frequency = transform.frequency_domain
        c = self.characteristic(frequency)
        a = 1 / np.pi
        result = []
        x = np.arange(n or 10)
        for m in x:
            d = np.sin(0.5 * frequency)
            d[0] = 1.0
            f = (
                np.sin(0.5 * (m + 1) * frequency)
                * (c * np.exp(-0.5 * Im * m * frequency)).real
                / d
            )
            f[0] = c[0].real  # type: ignore[index]
            if simpson_rule:
                result.append(a * simpson(f, x=frequency))
            else:
                result.append(a * np.trapz(f, frequency))
        pdf = np.maximum(np.diff(result, prepend=0), 0)
        return TransformResult(x=x, y=np.cumsum(pdf))
//  [python]
def integrateData(xdata,ydata,method='trapezoid'):
    """ Wrapper to integrate data. 

    Args:
        xdata (array-like)
        ydata (array-like)
        method (str, optional): Integration method. Defaults to 'trapezoid'. Possibilities include:
                                > 'simpson' : Simpson rule.
                                > 'trapezoid' : Trapezoidal rule.

    Returns:
        float: Area under ydata. 
    """
    checkType(xdata,'array')
    checkType(ydata,'array')
    xdata=np.array(xdata)
    ydata=np.array(ydata)

    if method=='simpson':
        return integrate.simps(ydata,xdata)

    elif method=='trapezoid':
        return integrate.trapezoid(ydata, xdata)

    else:
        logger.TBError("Unknown integration method",method)
//  [python]
def integrateData(xdata,ydata,method='trapezoid'):
    """ Wrapper to integrate data. 

    Args:
        xdata (array-like)
        ydata (array-like)
        method (str, optional): Integration method. Defaults to 'trapezoid'. Possibilities include:
                                > 'simpson' : Simpson rule.
                                > 'trapezoid' : Trapezoidal rule.

    Returns:
        float: Area under ydata. 
    """
    checkType(xdata,'array')
    checkType(ydata,'array')
    xdata=np.array(xdata)
    ydata=np.array(ydata)

    if method=='simpson':
        return integrate.simpson(ydata,xdata)

    elif method=='trapezoid':
        return integrate.trapezoid(ydata, xdata)

    else:
        logger.TBError("Unknown integration method",method)
//  [python]
def _integrate(self, integrand):
        return s(
            s(
                s(integrand,
                        dx=self.dxyz[2], axis=-1),
                dx=self.dxyz[1], axis=-1
            ), dx=self.dxyz[0], axis=-1)
//  [python]
def _integrate(self, integrand):
        return simpson(
            simpson(
                simpson(integrand,
                        dx=self.dxyz[2], axis=-1),
                dx=self.dxyz[1], axis=-1
            ), dx=self.dxyz[0], axis=-1)
//  [python]
def organ_analysis(organ, polyline, closest_nodes, stem_vector_mean=None):
    if len(polyline) <= 1:
        return None

    organ.info['pm_position_tip'] = tuple(polyline[-1])
    organ.info['pm_position_base'] = tuple(polyline[0])
    organ.info['pm_z_tip'] = polyline[-1][2]
    organ.info['pm_z_base'] = polyline[0][2]

    length = compute_length_organ(polyline)
    organ.info['pm_length'] = length
    normalized_curvilinear_abscissa = compute_curvilinear_abscissa(
        polyline, length)
    curvilinear_abscissa = compute_curvilinear_abscissa(polyline, 1)
    # Compute width
    width = compute_width_organ(closest_nodes)

    organ.info['pm_width_max'] = max(width)
    organ.info['pm_width_mean'] = sum(width) / float(len(width))
    organ.info['pm_surface'] = s.integrate.simpson(
        y= width, x=curvilinear_abscissa)

    fitted_width = compute_fitted_width(width, normalized_curvilinear_abscissa)
    organ.info['pm_fitted_width_max'] = max(fitted_width)
    organ.info['pm_fitted_width_mean'] = (sum(fitted_width) / float(len(
        fitted_width)))
    organ.info['pm_fitted_surface'] = s.integrate.simpson(
        y=fitted_width, x=curvilinear_abscissa)
    # Compute azimuth
    azimuth_angle, vector_mean = compute_azimuth_angle(polyline)
    organ.info['pm_vector_mean'] = vector_mean
    organ.info['pm_azimuth_angle'] = azimuth_angle

    inclination_angle = compute_inclination_angle(polyline)
    organ.info['pm_inclination_angle'] = inclination_angle

    if stem_vector_mean is not None and len(polyline) >= 4:
        insertion_angle, vector = compute_insertion_angle(
            polyline, stem_vector_mean)

        organ.info['pm_insertion_angle_vector'] = vector
        organ.info['pm_insertion_angle'] = insertion_angle

    return organ
//  [python]
def organ_analysis(organ, polyline, closest_nodes, stem_vector_mean=None):
    if len(polyline) <= 1:
        return None

    organ.info['pm_position_tip'] = tuple(polyline[-1])
    organ.info['pm_position_base'] = tuple(polyline[0])
    organ.info['pm_z_tip'] = polyline[-1][2]
    organ.info['pm_z_base'] = polyline[0][2]

    length = compute_length_organ(polyline)
    organ.info['pm_length'] = length
    normalized_curvilinear_abscissa = compute_curvilinear_abscissa(
        polyline, length)
    curvilinear_abscissa = compute_curvilinear_abscissa(polyline, 1)
    # Compute width
    width = compute_width_organ(closest_nodes)

    organ.info['pm_width_max'] = max(width)
    organ.info['pm_width_mean'] = sum(width) / float(len(width))
    organ.info['pm_surface'] = scipy.integrate.simpson(
        y= width, x=curvilinear_abscissa)

    fitted_width = compute_fitted_width(width, normalized_curvilinear_abscissa)
    organ.info['pm_fitted_width_max'] = max(fitted_width)
    organ.info['pm_fitted_width_mean'] = (sum(fitted_width) / float(len(
        fitted_width)))
    organ.info['pm_fitted_surface'] = scipy.integrate.simpson(
        y=fitted_width, x=curvilinear_abscissa)
    # Compute azimuth
    azimuth_angle, vector_mean = compute_azimuth_angle(polyline)
    organ.info['pm_vector_mean'] = vector_mean
    organ.info['pm_azimuth_angle'] = azimuth_angle

    inclination_angle = compute_inclination_angle(polyline)
    organ.info['pm_inclination_angle'] = inclination_angle

    if stem_vector_mean is not None and len(polyline) >= 4:
        insertion_angle, vector = compute_insertion_angle(
            polyline, stem_vector_mean)

        organ.info['pm_insertion_angle_vector'] = vector
        organ.info['pm_insertion_angle'] = insertion_angle

    return organ
//  [python]
B_val = s.simps(B_func(z_), z_)*(M)
F_val = s.simps(F_func(z_), z_)*(M)
//  [python]
B_val = integrate.simpson(B_func(z_), z_)*(M)
F_val = integrate.simpson(F_func(z_), z_)*(M)
//  [python]
def gridbasis_penalty_matrix_optimized(
    linear_operator: LinearDifferentialOperator,
    basis: _GridBasis,
) -> NDArrayFloat:
    """
    Optimized version for GridBasis.

    It evaluates the operator in the grid points.
    """
    n_points = basis.grid_points[0].shape[0]
    findiff_accuracy = 2

    evaluated_basis, domain_limits = _optimized_operator_evaluation_in_grid(
        linear_operator,
        basis.grid_points[0],
        findiff_accuracy=findiff_accuracy,
    )

    # If the operator does not have constant weights, the
    # optimized evaluation is not implemented.
    if evaluated_basis is NotImplemented:
        return NotImplemented

    # The support of the result of applying the linear operator
    # is a small subset of the grid points. We calculate the
    # maximum number of points to the left and right of the
    # point where the linear operator is applied that can be
    # different from zero.

    max_domain_width = np.max(
        np.abs(domain_limits[:, 0] - domain_limits[:, 1]),
    )

    # Precompute the simpson quadrature for the entire domain.
    # This is done to avoid computing it for each subinterval of integration.
    quadrature = scipy.integrate.simps(
        np.identity(n_points),
        x=basis.grid_points[0],
    )

    product_matrix = np.zeros((basis.n_basis, basis.n_basis))
    for i in range(n_points):
        # Maximum index of another function with not-disjoint support
        max_no_disjoint_index = min(n_points, i + 2 * max_domain_width)

        for j in range(i, max_no_disjoint_index):
            if domain_limits[i, 1] < domain_limits[j, 0]:
                continue

            left_lim = min(
                domain_limits[i, 0],
                domain_limits[j, 0],
            )
            right_lim = max(
                domain_limits[i, 1],
                domain_limits[j, 1],
            )

            # The right limit of the interval is excluded when slicing
            right_lim += 1

            # Limit both the multiplication and the integration to
            # the interval where the functions are not 0.
            operator_product = (
                evaluated_basis[i, left_lim:right_lim]
                * evaluated_basis[j, left_lim:right_lim]
            )
            sub_quadrature = quadrature[left_lim:right_lim]

            product_matrix[i, j] = np.dot(operator_product, sub_quadrature)
            product_matrix[j, i] = product_matrix[i, j]

    return product_matrix
//  [python]
def gridbasis_penalty_matrix_optimized(
    linear_operator: LinearDifferentialOperator,
    basis: _GridBasis,
) -> NDArrayFloat:
    """
    Optimized version for GridBasis.

    It evaluates the operator in the grid points.
    """
    n_points = basis.grid_points[0].shape[0]
    findiff_accuracy = 2

    evaluated_basis, domain_limits = _optimized_operator_evaluation_in_grid(
        linear_operator,
        basis.grid_points[0],
        findiff_accuracy=findiff_accuracy,
    )

    # If the operator does not have constant weights, the
    # optimized evaluation is not implemented.
    if evaluated_basis is NotImplemented:
        return NotImplemented

    # The support of the result of applying the linear operator
    # is a small subset of the grid points. We calculate the
    # maximum number of points to the left and right of the
    # point where the linear operator is applied that can be
    # different from zero.

    max_domain_width = np.max(
        np.abs(domain_limits[:, 0] - domain_limits[:, 1]),
    )

    # Precompute the simpson quadrature for the entire domain.
    # This is done to avoid computing it for each subinterval of integration.
    quadrature = scipy.integrate.simpson(
        np.identity(n_points),
        x=basis.grid_points[0],
    )

    product_matrix = np.zeros((basis.n_basis, basis.n_basis))
    for i in range(n_points):
        # Maximum index of another function with not-disjoint support
        max_no_disjoint_index = min(n_points, i + 2 * max_domain_width)

        for j in range(i, max_no_disjoint_index):
            if domain_limits[i, 1] < domain_limits[j, 0]:
                continue

            left_lim = min(
                domain_limits[i, 0],
                domain_limits[j, 0],
            )
            right_lim = max(
                domain_limits[i, 1],
                domain_limits[j, 1],
            )

            # The right limit of the interval is excluded when slicing
            right_lim += 1

            # Limit both the multiplication and the integration to
            # the interval where the functions are not 0.
            operator_product = (
                evaluated_basis[i, left_lim:right_lim]
                * evaluated_basis[j, left_lim:right_lim]
            )
            sub_quadrature = quadrature[left_lim:right_lim]

            product_matrix[i, j] = np.dot(operator_product, sub_quadrature)
            product_matrix[j, i] = product_matrix[i, j]

    return product_matrix
//  [python]
def test_pdf_unity_area(self):
        from scipy.integrate import simps
        # PDF should integrate to one
        p = stats.genexpon.pdf(np.arange(0, 10, 0.01), 0.5, 0.5, 2.0)
        assert_almost_equal(simps(p, dx=0.01), 1, 1)
//  [python]
def test_pdf_unity_area(self):
        from scipy.integrate import simpson
        # PDF should integrate to one
        p = stats.genexpon.pdf(np.arange(0, 10, 0.01), 0.5, 0.5, 2.0)
        assert_almost_equal(simpson(p, dx=0.01), 1, 1)
//  [python]
def broadband_albedo(
    wavelength: ArrayOrScalar,
    totflux: ArrayOrScalar,
    dir_frac: ArrayOrScalar,
    SSA: ArrayOrScalar,
    **kwargs,
):
    """compute the broadband albedo of a snowpack specified by the profiles of SSA and density using TARTES. Refer to
    the :py:func:`albedo` function for a detailed description of the parameters.

    To compute the totflux and dir_frac for a simple atmosphere, see  :py:func:`atmospheric_incident_spectrum` function
    provided in this package.

    :param wavelength: wavelength (m)
    :type wavelength: array
    :param totflux: spectrum of incident direct+diffuse radiation  at the surface
    :param dir_frac: spectrum of fraction of the direct radiation
    :param SSA: surface specific area (m^2/kg) for each layer
    :type SSA: array
    :param **kwagrs: all the other optional parametres of the :py:func:`albedo` function

    :returns: broadband albedo
    """

    kwargs["return_dir_diff"] = True
    dir_frac = np.atleast_1d(dir_frac)
    totflux = np.atleast_1d(totflux)

    albedo_dir, albedo_diff = albedo(wavelength, SSA, dir_frac=dir_frac, **kwargs)

    broadband_albedo = s.integrate.simpson(
        totflux * (dir_frac * albedo_dir + (1.0 - dir_frac) * albedo_diff), x=wavelength
    ) / s.integrate.simpson(totflux, x=wavelength)

    return broadband_albedo
//  [python]
def broadband_albedo(
    wavelength: ArrayOrScalar,
    totflux: ArrayOrScalar,
    dir_frac: ArrayOrScalar,
    SSA: ArrayOrScalar,
    **kwargs,
):
    """compute the broadband albedo of a snowpack specified by the profiles of SSA and density using TARTES. Refer to
    the :py:func:`albedo` function for a detailed description of the parameters.

    To compute the totflux and dir_frac for a simple atmosphere, see  :py:func:`atmospheric_incident_spectrum` function
    provided in this package.

    :param wavelength: wavelength (m)
    :type wavelength: array
    :param totflux: spectrum of incident direct+diffuse radiation  at the surface
    :param dir_frac: spectrum of fraction of the direct radiation
    :param SSA: surface specific area (m^2/kg) for each layer
    :type SSA: array
    :param **kwagrs: all the other optional parametres of the :py:func:`albedo` function

    :returns: broadband albedo
    """

    kwargs["return_dir_diff"] = True
    dir_frac = np.atleast_1d(dir_frac)
    totflux = np.atleast_1d(totflux)

    albedo_dir, albedo_diff = albedo(wavelength, SSA, dir_frac=dir_frac, **kwargs)

    broadband_albedo = scipy.integrate.simpson(
        totflux * (dir_frac * albedo_dir + (1.0 - dir_frac) * albedo_diff), x=wavelength
    ) / scipy.integrate.simpson(totflux, x=wavelength)

    return broadband_albedo
//  [python]
def self_diffusivity_gk_odd(self, start=0, stop=0, step=1):
        """
        Returns a self-diffusivity value using ``scipy.integrate.simpson``.
        Recommended for use with an odd number of evenly spaced data points.
        Analysis must be run prior to computing self-diffusivity.

        Parameters
        ----------
        start : Optional[int]
            The first frame of ``self.results.timeseries``
            used for the calculation.
        stop : Optional[int]
            The frame of ``self.results.timeseries`` to stop at
            for the calculation, non-inclusive.
        step : Optional[int]
            Number of frames to skip between each frame used
            for the calculation.

        Returns
        -------
        `numpy.float64`
            The calculated self-diffusivity value for the analysis.
        """
        if not self._run_called:
            raise RuntimeError(
                "Analysis must be run prior to computing self-diffusivity"
            )

        stop = self.n_frames if stop == 0 else stop

        return (
            integrate.simps(
                self.results.timeseries[start:stop:step],
                self.times[start:stop:step],
            )
            / self.dim_fac
        )
//  [python]
def self_diffusivity_gk_odd(self, start=0, stop=0, step=1):
        """
        Returns a self-diffusivity value using ``scipy.integrate.simpson``.
        Recommended for use with an odd number of evenly spaced data points.
        Analysis must be run prior to computing self-diffusivity.

        Parameters
        ----------
        start : Optional[int]
            The first frame of ``self.results.timeseries``
            used for the calculation.
        stop : Optional[int]
            The frame of ``self.results.timeseries`` to stop at
            for the calculation, non-inclusive.
        step : Optional[int]
            Number of frames to skip between each frame used
            for the calculation.

        Returns
        -------
        `numpy.float64`
            The calculated self-diffusivity value for the analysis.
        """
        if not self._run_called:
            raise RuntimeError(
                "Analysis must be run prior to computing self-diffusivity"
            )

        stop = self.n_frames if stop == 0 else stop

        return (
            integrate.simpson(
                self.results.timeseries[start:stop:step],
                self.times[start:stop:step],
            )
            / self.dim_fac
        )
//  [python]
def test_simps_weights(test_fct):
    """Test weights for Simpson rule."""
    for num in [100, 101]:  # test even as well as odd!
        tt, dt = np.linspace(0, 10, num, retstep=True)
        gf = test_fct(tt)
        coeff = gt.fourier._simps_weight(dt, gf_t=gf, endpoint=True)
        assert_allclose(coeff.sum(), s.simpson(gf, dx=dt, even='first'), rtol=1e-14)
        gf[-2:] = 0
        coeff = gt.fourier._trapz_weight(dt, gf_t=gf, endpoint=False)
        assert_allclose(coeff.sum(), np.trapz(gf, dx=dt), rtol=1e-14)
//  [python]
def test_simps_weights(test_fct):
    """Test weights for Simpson rule."""
    for num in [100, 101]:  # test even as well as odd!
        tt, dt = np.linspace(0, 10, num, retstep=True)
        gf = test_fct(tt)
        coeff = gt.fourier._simps_weight(dt, gf_t=gf, endpoint=True)
        assert_allclose(coeff.sum(), simpson(gf, dx=dt, even='first'), rtol=1e-14)
        gf[-2:] = 0
        coeff = gt.fourier._trapz_weight(dt, gf_t=gf, endpoint=False)
        assert_allclose(coeff.sum(), np.trapz(gf, dx=dt), rtol=1e-14)
//  [python]
def integrate(self, start=None, end=None, method='simps'):
        """Compute the integrated value between ``start`` and ``end``.

        Parameters
        ----------
        start : float, optional
            Lower wavelength bound. If not specified (default),
            ``min(self.wave)`` is used.
        end : float, optional
            Upper wavelength bound. If not specified (default),
            ``max(self.wave)`` is used.
        method : {'simps', 'trapz'}, optional
            Numerical integration method. 'simps' (default) is better for smooth
            data while 'trapz' is better for linear data.

        Returns
        -------
        result : float
            Integral as approximated by ``interp_method``

        """
        if start is None:
            start = np.min(self.wave)
        if end is None:
            end = np.max(self.wave)

        indices = np.intersect1d(np.where(self.wave >= start),
                                 np.where(self.wave <= end))
        wave = self.wave[indices]
        value = self.value[indices]

        if method == 'simps':
            result = scipy.integrate.simps(x=wave, y=value)
        elif method == 'trapz':
            result = np.trapz(value, wave)
        else:
            raise ValueError('Unknown method ', method)

        return result
//  [python]
def integrate(self, start=None, end=None, method='simps'):
        """Compute the integrated value between ``start`` and ``end``.

        Parameters
        ----------
        start : float, optional
            Lower wavelength bound. If not specified (default),
            ``min(self.wave)`` is used.
        end : float, optional
            Upper wavelength bound. If not specified (default),
            ``max(self.wave)`` is used.
        method : {'simps', 'trapz'}, optional
            Numerical integration method. 'simps' (default) is better for smooth
            data while 'trapz' is better for linear data.

        Returns
        -------
        result : float
            Integral as approximated by ``interp_method``

        """
        if start is None:
            start = np.min(self.wave)
        if end is None:
            end = np.max(self.wave)

        indices = np.intersect1d(np.where(self.wave >= start),
                                 np.where(self.wave <= end))
        wave = self.wave[indices]
        value = self.value[indices]

        if method == 'simps':
            result = scipy.integrate.simpson(x=wave, y=value)
        elif method == 'trapz':
            result = np.trapz(value, wave)
        else:
            raise ValueError('Unknown method ', method)

        return result
//  [python]
def generateSpline(points : np.ndarray, k=3, simpson_subintervals = 12):
    if not (simpson_subintervals%2)==0:
        raise ValueError("Must use even number of subintervals for Simpson's method")
    # points_aug : np.ndarray = points[:-1].copy()
    if np.linalg.norm(points[-1]-points[0], ord=2)>1E-6:
        points_aug = np.concatenate([points, points[None,0]], axis=0)
    else:
        points_aug = points.copy()
    euclidean_distances : np.ndarray = np.zeros_like(points_aug[:,0])
    euclidean_distances[1:] = np.cumsum(np.linalg.norm(points_aug[1:] - points_aug[:-1], ord=2, axis=1))
    splinex = euclidean_distances

    fake_spline : scipy.interpolate.BSpline = scipy.interpolate.make_interp_spline(splinex, points_aug, k=k, bc_type="periodic")
    fake_spline_der : scipy.interpolate.BSpline = fake_spline.derivative()

    true_distances : np.ndarray = np.zeros_like(splinex)
    for i in range(1, true_distances.shape[0]):
        x0 = splinex[i-1]
        x1 = splinex[i]
        xvec : np.ndarray = np.linspace(x0, x1, simpson_subintervals + 1)
        spline_norms : np.ndarray = np.linalg.norm(fake_spline_der(xvec), ord=2.0, axis=1)
        true_distances[i] = true_distances[i-1] + scipy.integrate.simps(spline_norms, xvec)
    return true_distances, points_aug, scipy.interpolate.make_interp_spline(true_distances, points_aug, k=k, bc_type="periodic")
//  [python]
def generateSpline(points : np.ndarray, k=3, simpson_subintervals = 12):
    if not (simpson_subintervals%2)==0:
        raise ValueError("Must use even number of subintervals for Simpson's method")
    # points_aug : np.ndarray = points[:-1].copy()
    if np.linalg.norm(points[-1]-points[0], ord=2)>1E-6:
        points_aug = np.concatenate([points, points[None,0]], axis=0)
    else:
        points_aug = points.copy()
    euclidean_distances : np.ndarray = np.zeros_like(points_aug[:,0])
    euclidean_distances[1:] = np.cumsum(np.linalg.norm(points_aug[1:] - points_aug[:-1], ord=2, axis=1))
    splinex = euclidean_distances

    fake_spline : scipy.interpolate.BSpline = scipy.interpolate.make_interp_spline(splinex, points_aug, k=k, bc_type="periodic")
    fake_spline_der : scipy.interpolate.BSpline = fake_spline.derivative()

    true_distances : np.ndarray = np.zeros_like(splinex)
    for i in range(1, true_distances.shape[0]):
        x0 = splinex[i-1]
        x1 = splinex[i]
        xvec : np.ndarray = np.linspace(x0, x1, simpson_subintervals + 1)
        spline_norms : np.ndarray = np.linalg.norm(fake_spline_der(xvec), ord=2.0, axis=1)
        true_distances[i] = true_distances[i-1] + scipy.integrate.simpson(spline_norms, xvec)
    return true_distances, points_aug, scipy.interpolate.make_interp_spline(true_distances, points_aug, k=k, bc_type="periodic")
//  [python]
def integrate(
        self: T,
        *,
        domain: Optional[DomainRange] = None,
    ) -> NDArrayFloat:
        """Integrate the FDataIrregular object.

        The integration can only be performed over 1 dimensional domains.

        For a vector valued function the vector of integrals will be
        returned.

        Args:
            domain: tuple with the domain ranges for each dimension of the
                domain. If None, the domain range of the object will be used.

        Returns:
            NumPy array of size (``n_samples``, ``dim_codomain``)
            with the integrated data.

        Examples:
            >>> fdata = FDataIrregular(
            ...     values=[[2, -1], [2, 3], [5, -2], [1, -1], [1, -1]],
            ...     points=[[4], [5], [6], [0], [2]],
            ...     start_indices=[0, 3],
            ... )
            >>> fdata.integrate()
            array([[ 5.,  3.],
                   [ 2., -2.]])
        """
        if self.dim_domain != 1:
            raise NotImplementedError(
                "Integration only implemented for 1D domains.",
            )

        if domain is not None:
            data = self.restrict(domain)
        else:
            data = self

        values_list = np.split(data.values, data.start_indices[1:])
        points_list = np.split(data.points, data.start_indices[1:])
        return np.array([
            s.integrate.simpson(y, x, axis=0)
            for y, x in zip(values_list, points_list)
        ])
//  [python]
def integrate(
        self: T,
        *,
        domain: Optional[DomainRange] = None,
    ) -> NDArrayFloat:
        """Integrate the FDataIrregular object.

        The integration can only be performed over 1 dimensional domains.

        For a vector valued function the vector of integrals will be
        returned.

        Args:
            domain: tuple with the domain ranges for each dimension of the
                domain. If None, the domain range of the object will be used.

        Returns:
            NumPy array of size (``n_samples``, ``dim_codomain``)
            with the integrated data.

        Examples:
            >>> fdata = FDataIrregular(
            ...     values=[[2, -1], [2, 3], [5, -2], [1, -1], [1, -1]],
            ...     points=[[4], [5], [6], [0], [2]],
            ...     start_indices=[0, 3],
            ... )
            >>> fdata.integrate()
            array([[ 5.,  3.],
                   [ 2., -2.]])
        """
        if self.dim_domain != 1:
            raise NotImplementedError(
                "Integration only implemented for 1D domains.",
            )

        if domain is not None:
            data = self.restrict(domain)
        else:
            data = self

        values_list = np.split(data.values, data.start_indices[1:])
        points_list = np.split(data.points, data.start_indices[1:])
        return np.array([
            scipy.integrate.simpson(y, x, axis=0)
            for y, x in zip(values_list, points_list)
        ])
//  [python]
def compute_auc(self):
        dx = self.thresholds[1] - self.thresholds[0]
        perfect_predictor = scipy.integrate.simpson(np.ones_like(self.thresholds), dx=dx)

        pr, re, f1 = self.compute_at_all_thresholds()

        pr_area = scipy.integrate.simpson(pr, dx=dx)
        norm_pr_area = pr_area / perfect_predictor

        re_area = scipy.integrate.simpson(re, dx=dx)
        norm_re_area = re_area / perfect_predictor

        f1_area = scipy.integrate.simpson(f1, dx=dx)
        norm_f1_area = f1_area / perfect_predictor

        # print('computing area under curve')
        # print('precision: {}'.format(norm_pr_area))
        # print('recall: {}'.format(norm_re_area))
        # print('fscore: {}'.format(norm_f1_area))

        return norm_pr_area, norm_re_area, norm_f1_area
//  [python]
def simpsons_rule(x, y):
    global nparray_x, nparray_y, result
    nparray_x = np.append(nparray_x, x)
    nparray_y = np.append(nparray_y, y)
    result = s.simps(nparray_y, nparray_x)
    return result
//  [python]
def simpsons_rule(x, y):
    global nparray_x, nparray_y, result
    nparray_x = np.append(nparray_x, x)
    nparray_y = np.append(nparray_y, y)
    result = integrate.simpson(nparray_y, nparray_x)
    return result
//  [python]
def computeTangentsAndNormals(r, X, k = 3, ds = 1.0, ref = np.array([0.0,1.0,0.0], dtype=np.float64)):
    
    # finaldelta = np.linalg.norm(X[-1] - X[0], ord=2)
    # Xaug = np.concatenate([X, X[0].reshape(1,-1)], axis=0)
    # raug = np.concatenate([r, np.asarray([r[-1]+finaldelta])], axis=0)
    # raug = raug-raug[0]
    garbagespline : interp.BSpline = interp.make_interp_spline(r, X, k=k, bc_type="periodic")
    garbagesplineder : interp.BSpline = garbagespline.derivative()
    truedistances : np.ndarray = np.zeros_like(r)
    for i in range(1, truedistances.shape[0]):
        rsumsamp : np.ndarray = np.linspace(r[i-1], r[i], num=5)
        velsubsamp : np.ndarray = np.linalg.norm(garbagesplineder(rsumsamp), ord=2, axis=1)
        truedistances[i] = truedistances[i-1] + integrate.simps(velsubsamp, x=rsumsamp)

    spline : interp.BSpline = interp.make_interp_spline(truedistances, X, k=k, bc_type="periodic")
    tangentspline : interp.BSpline = spline.derivative(nu=1)
    rsamp = np.linspace(truedistances[0], truedistances[-1]-ds, num = int(round(truedistances[-1]/ds)))
    points = spline(rsamp)
    tangents = tangentspline(rsamp)
    speeds = np.linalg.norm(tangents, ord=2, axis=1)
    unit_tangents = tangents/speeds[:,np.newaxis]

    numpoints = points.shape[0]
    ref_ = np.stack([ref for asdf in range(numpoints)])
    v1 = np.cross(unit_tangents, ref_)
    v1 = v1/np.linalg.norm(v1, axis=1, ord=2)[:,np.newaxis]
    v2 =  np.cross(v1, unit_tangents)
    v2 = v2/np.linalg.norm(v2, axis=1, ord=2)[:,np.newaxis]

    normals = np.cross(v2, unit_tangents)
    unit_normals = normals/np.linalg.norm(normals, axis=1, ord=2)[:,np.newaxis]

    return spline, points, speeds, unit_tangents, unit_normals, rsamp
//  [python]
def computeTangentsAndNormals(r, X, k = 3, ds = 1.0, ref = np.array([0.0,1.0,0.0], dtype=np.float64)):
    
    # finaldelta = np.linalg.norm(X[-1] - X[0], ord=2)
    # Xaug = np.concatenate([X, X[0].reshape(1,-1)], axis=0)
    # raug = np.concatenate([r, np.asarray([r[-1]+finaldelta])], axis=0)
    # raug = raug-raug[0]
    garbagespline : interp.BSpline = interp.make_interp_spline(r, X, k=k, bc_type="periodic")
    garbagesplineder : interp.BSpline = garbagespline.derivative()
    truedistances : np.ndarray = np.zeros_like(r)
    for i in range(1, truedistances.shape[0]):
        rsumsamp : np.ndarray = np.linspace(r[i-1], r[i], num=5)
        velsubsamp : np.ndarray = np.linalg.norm(garbagesplineder(rsumsamp), ord=2, axis=1)
        truedistances[i] = truedistances[i-1] + integrate.simpson(velsubsamp, x=rsumsamp)

    spline : interp.BSpline = interp.make_interp_spline(truedistances, X, k=k, bc_type="periodic")
    tangentspline : interp.BSpline = spline.derivative(nu=1)
    rsamp = np.linspace(truedistances[0], truedistances[-1]-ds, num = int(round(truedistances[-1]/ds)))
    points = spline(rsamp)
    tangents = tangentspline(rsamp)
    speeds = np.linalg.norm(tangents, ord=2, axis=1)
    unit_tangents = tangents/speeds[:,np.newaxis]

    numpoints = points.shape[0]
    ref_ = np.stack([ref for asdf in range(numpoints)])
    v1 = np.cross(unit_tangents, ref_)
    v1 = v1/np.linalg.norm(v1, axis=1, ord=2)[:,np.newaxis]
    v2 =  np.cross(v1, unit_tangents)
    v2 = v2/np.linalg.norm(v2, axis=1, ord=2)[:,np.newaxis]

    normals = np.cross(v2, unit_tangents)
    unit_normals = normals/np.linalg.norm(normals, axis=1, ord=2)[:,np.newaxis]

    return spline, points, speeds, unit_tangents, unit_normals, rsamp
//  [python]
def evaluate_ages(self, lnJz_sample, eval_grid=np.linspace(0, 14, 1000), k=0):
        """Evaluate the age posterior for a given posterior index (k) and given lnJz over a grid"""

        from scipy.stats import norm
        from scipy.integrate import simps as scipy_simpson
        from tqdm import tqdm

        if not hasattr(self, 'eval_spline'):
            self.evaluate_spline(eval_grid=eval_grid, k=0)
        
        self.age_knot_vals = self.inf_data.posterior['age_knot_vals'].values.reshape(-1, self.inf_data.posterior['age_knot_vals'].values.shape[-1])[k]
        self.V_samp = np.exp(self.inf_data.posterior['lnV'].values.reshape(-1)[k])

        eval_pdf = []

        if isinstance(lnJz_sample, float) or isinstance(lnJz_sample, int):

            P = norm.pdf(lnJz_sample, loc=self.eval_spline, scale=np.sqrt(self.V_samp))
            P /= scipy_simpson(x=eval_grid, y=P)

            eval_pdf = P

        else:

            for n in tqdm(range(len(lnJz_sample))):
                P = norm.pdf(lnJz_sample[n], loc=self.eval_spline, scale=np.sqrt(self.V_samp))
                P /= scipy_simpson(x=eval_grid, y=P)

                eval_pdf.append(P)

        self.eval_grid = eval_grid
        self.eval_pdf = np.array(eval_pdf)

        return eval_grid, np.array(eval_pdf)
//  [python]
def evaluate_ages(self, lnJz_sample, eval_grid=np.linspace(0, 14, 1000), k=0):
        """Evaluate the age posterior for a given posterior index (k) and given lnJz over a grid"""

        from scipy.stats import norm
        from scipy.integrate import simpson as scipy_simpson
        from tqdm import tqdm

        if not hasattr(self, 'eval_spline'):
            self.evaluate_spline(eval_grid=eval_grid, k=0)
        
        self.age_knot_vals = self.inf_data.posterior['age_knot_vals'].values.reshape(-1, self.inf_data.posterior['age_knot_vals'].values.shape[-1])[k]
        self.V_samp = np.exp(self.inf_data.posterior['lnV'].values.reshape(-1)[k])

        eval_pdf = []

        if isinstance(lnJz_sample, float) or isinstance(lnJz_sample, int):

            P = norm.pdf(lnJz_sample, loc=self.eval_spline, scale=np.sqrt(self.V_samp))
            P /= scipy_simpson(x=eval_grid, y=P)

            eval_pdf = P

        else:

            for n in tqdm(range(len(lnJz_sample))):
                P = norm.pdf(lnJz_sample[n], loc=self.eval_spline, scale=np.sqrt(self.V_samp))
                P /= scipy_simpson(x=eval_grid, y=P)

                eval_pdf.append(P)

        self.eval_grid = eval_grid
        self.eval_pdf = np.array(eval_pdf)

        return eval_grid, np.array(eval_pdf)