The ddg.nonexact module

The module ddg.nonexact contains tools to manage and use global defaults for tolerances used in nonexact computations. Here’s how to write your own nonexact functions and classes:

The general concept is quite simple: We write small functions for elementary nonexact computations that will use the global tolerances if the atol or rtol given to them is None. A very simple example is ddg.nonexact.isclose(), which just wraps numpy.isclose():

def isclose(a, b, rtol=None, atol=None, equal_nan=False):
    """Wrapper for numpy.isclose that uses global tolerance defaults."""
    rtol_ = get_tol_defaults()["rtol"] if rtol is None else rtol
    atol_ = get_tol_defaults()["atol"] if atol is None else atol
    return np.isclose(a, b, rtol=rtol_, atol=atol_, equal_nan=equal_nan)

The ddg.nonexact module contains other functions like ddg.nonexact.isclose(), check its contents to see if it has what you need. Otherwise, you might have to add a function in the style of ddg.nonexact.isclose().

When you write a function with atol and rtol arguments, proceed as you normally would, but use these functions where you would normally use numpy functions or explicit computations. Your function can now handle None as a value of atol and rtol. Here is a simple example of a finished nonexact function:

def is_symmetric(A, atol=1e-13, rtol=None):
    """Checks whether a square matrix is symmetric.

    Parameters
    ----------
    A : numpy.ndarray of shape (n, n)
    atol : float (default=1e-13)
    rtol : float (default=None)
        This function uses the global tolerance defaults if `atol` or `rtol` are
        set to None. See :py:mod:`ddg.nonexact` for details.

    Returns
    -------
    bool
    """
    return nonexact.isclose(np.linalg.norm(A - A.T), 0.0, atol=atol, rtol=rtol)

When you’re writing a class, give it attributes atol and rtol that can contain a float or None. You can then use our nonexact functions inside methods and pass self.atol and self.rtol to them. Here is an example of a noneaxct method (of ddg.geometry.quadrics.Quadric).

    def conjugate(self, S1, S2):
        """Conjugacy of two subspaces.

        Whether two subspaces are conjugate, i.e. if approximately
        ``inner_product(v, w) == 0`` for all v in S1 and w in S2.

        Parameters
        ----------
        S1, S2 : ddg.geometry.subspaces.Subspace or numpy.ndarray
            Subspaces contained in self.subspace. Arrays will be interpreted as
            matrices whose columns are points in homogeneous coordinates. In
            particular, 1D arrays are simply points in homogeneous coordinates.

        Returns
        -------
        bool
        """
        S1 = self._coordinate_helper(S1)
        S2 = self._coordinate_helper(S2)
        eps = S1.T @ self.matrix @ S2
        return nonexact.allclose(eps, 0.0, atol=self.atol, rtol=self.rtol)