--***********************************************
--***********************************************
--Documentation for testIdeals.m2
--***********************************************
--***********************************************

doc ///
    Key
        QGorensteinGenerator
        (QGorensteinGenerator, ZZ, Ring)
        (QGorensteinGenerator, Ring)
    Headline
        find an element representing the Frobenius trace map of a Q-Gorenstein ring
    Usage
        QGorensteinGenerator(e, R)
        QGorensteinGenerator(R)
    Inputs
        e: ZZ
            the degree in which to search
        R: Ring
            a $\mathbb{Q}$-Gorenstein ring
    Outputs
        :RingElement
	    representing the Frobenius trace map of {\tt R}
    Description
        Text
            Suppose that $R$ is a ring such that $(p^e-1)K_R$ is linearly equivalent to zero (this is the case, for example, if $R$ is $\mathbb{Q}$-Gorenstein with index not divisible by $p$).
            Then if we write $R = S/I$, where $S$ is a polynomial ring, we have that $I^{[p^e]}:I = uS + I^{[p^e]}$ for some $u \in S$.
            By Fedder's criterion, this element $u$ represents the generator of the $R^{1/p^e}$-module Hom($R^{1/p^e}$,$R$).
            For example, if $I$ is principal, generated by $f$, then we may take $u = f^{ p^e-1}$.

            The function {\tt QGorensteinGenerator} produces the element $u$ described above.  
	    If the user does not specify a positive integer $e$, it assumes $e = 1$.
        Example
            S = ZZ/3[x,y,z];
            f = x^2*y - z^2;
            I = ideal f;
            R = S/I;
            u = QGorensteinGenerator(1, R)
            u % I^3 == f^2 % I^3
        Text
            If {\it Macaulay2} does not recognize that $I^{[p^e]}:I / I^{[p^e]}$ is principal, an error is thrown, which will also happen if $R$ is not $\mathbb{Q}$-Gorenstein of the appropriate index.  
	    Note that in the nongraded case {\it Macaulay2} is not guaranteed to find minimal generators of principally generated modules.
///

doc ///
    Key
        testElement
        (testElement, Ring)
        [testElement, AssumeDomain]
    Headline
        find a test element of a ring
    Usage
        testElement(R)
    Inputs
        R: Ring
            a quotient of a polynomial ring
        AssumeDomain => Boolean
            assumes the ring is a domain
    Outputs
        :RingElement
	    a test element of {\tt R}
    Description
        Text
            Given $R = S/I$, where $S$ is a polynomial ring, the function {\tt testElement} finds an element of the ambient ring $S$ whose image in $R$ is a test element of $R$. This is done by finding a minor of the jacobian of $I$ that does not lie in any minimal prime of $I$. This function considers random minors until one is found, instead of computing all minors. Thus, repeated calls will not always produce the same answer.
        Example
            R = ZZ/11[x,y,z]/(x^3 + y^3 + z^3);
	    apply(1..5, i -> testElement(R))
        Text
            If the option {\tt AssumeDomain} (default value {\tt false}) is set to {\tt true}, then {\tt testElement} does not compute the minimal primes of $I$. 
	    This can result in a substantial speedup in some cases.
///

doc ///
    Key
        AssumeDomain
    Headline
        an option to assume a ring is a domain
    Description
        Text
            {\tt AssumeDomain} is an option used in various functions, to assume that a ring is an integral domain.
///

doc ///
    Key
        MaxCartierIndex
    Headline
        an option to specify the maximum number to consider when computing the Cartier index of a divisor
    Description
        Text
	    Some functions need to search for the smallest positive integer $N$ such that $N$ times a divisor (usually the canonical divisor) is Cartier. 
	    The option {\tt MaxCartierIndex} is used to specify the largest integer to be considered in this search.
///


doc ///
    Key
        QGorensteinIndex
    Headline
        an option to specify the index of the canonical divisor, if known
    Description
        Text
             When working in a $\mathbb{Q}$-Gorenstein ring $R$, frequently we must find a positive integer $N$ such that $N K_R$ is Cartier. 
	     This option allows this search to be bypassed if this integer is already known, by setting {\tt QGorensteinIndex => N}.
///

doc ///
    Key
        DepthOfSearch
    Headline
        an option to specify how hard to search for something
    Description
        Text
             This option is used to tell certain functions how hard to look for an answer.  Increasing it too much can make functions take a lot of time and resources.  Making it too small may mean that an incorrect or incomplete answer is given.  See the documentation for each function.
///

doc ///
    Key
        testIdeal
        (testIdeal, Ring)
        (testIdeal, Number, RingElement)
        (testIdeal, List, List)
        [testIdeal, AssumeDomain]
        [testIdeal, FrobeniusRootStrategy]
        [testIdeal, MaxCartierIndex]
        [testIdeal, QGorensteinIndex]
    Headline
        compute a test ideal in a Q-Gorenstein ring
    Usage
        testIdeal(R)
        testIdeal(t, f)
        testIdeal(tList, fList)
    Inputs
        R:Ring
	    a $\mathbb{Q}$-Gorenstein ring
        f:RingElement
            the element in a pair
        t:Number
            the formal exponent to which {\tt f} is raised
        fList:List
            consisting of ring elements {\tt f_1,\ldots,f_n}, for a pair
        tList:List
            consisting of formal exponents {\tt t_1,\ldots,t_n} for the elements of {\tt fList}
        AssumeDomain => Boolean
            assumes the ring is an integral domain
        FrobeniusRootStrategy => Symbol
            selects the strategy for internal {\tt frobeniusRoot} calls
        MaxCartierIndex => ZZ
            sets the maximum $\mathbb{Q}$-Gorenstein index to search for 
        QGorensteinIndex => ZZ
            specifies the $\mathbb{Q}$-Gorenstein index of the ring
    Outputs
        :Ideal
	    the test ideal {\tt \tau(R)}, {\tt \tau(R,f^{t})}, or {\tt \tau(R,f_1^{t_1}\ldots f_n^{t_n})}, depending on the arguments passed
    Description
        Text
            Given a normal $\mathbb{Q}$-Gorenstein ring $R$, {\tt testIdeal(R)} simply computes the test ideal {\tt \tau}($R$).
        Example
            R = ZZ/5[x,y,z]/(x^3 + y^3 + z^3);
            testIdeal(R)
        Example
            S = ZZ/5[x,y,z,w];
            T = ZZ/5[a,b];
            f = map(T, S, {a^3, a^2*b, a*b^2, b^3});
            R = S/(ker f);
            testIdeal(R)
        Text
            Given a nonnegative rational number $t$ and an element $f$ of a normal $\mathbb{Q}$-Gorenstein ring $R$, {\tt testIdeal(t,f)} computes the test ideal {\tt \tau}($R$, $f^{ t}$).
        Example
            R = ZZ/5[x,y,z];
            f = y^2 - x^3;
	    apply({1/2, 4/5, 5/6, 1}, t -> testIdeal(t, f) )
            R = ZZ/7[x,y,z];
            f = y^2 - x^3;
	    apply({1/2, 4/5, 5/6, 1}, t -> testIdeal(t, f) )
        Text
            The ring $R$ need not be a polynomial ring, as the next example illustrates.
        Example
            R = ZZ/11[x,y,z]/(x^2 - y*z);
            testIdeal(1/2, y)
            testIdeal(1/3, y)
        Text
            Given nonnegative rational numbers $t_1, t_2, \ldots$ and ring elements $f_1, f_2, \ldots$, {\tt testIdeal(\{t_1,t_2,\ldots\},\{f_1,f_2,\ldots\})} computes the test ideal {\tt \tau}($R$, $f_1^{t_1} f_2^{t_2}\cdots$).
        Example
            R = ZZ/7[x,y];
            L = {x, y, x + y};
            f = x*y*(x + y);
            testIdeal({2/3, 2/3, 2/3}, L)
            testIdeal(2/3, f)
            testIdeal({3/4, 2/3, 3/5}, L)
        Text
            It is often more efficient to pass a list, as opposed to finding a common denominator and passing a single element, since {\tt testIdeal} can do things in a more intelligent way for such a list.
        Example
            time testIdeal({3/4, 2/3, 3/5}, L)
            time testIdeal(1/60, x^45*y^40*(x + y)^36)
        Text
            The option {\tt AssumeDomain} (default value {\tt false}) is used when finding a test element.  
	    The option {\tt FrobeniusRootStrategy} (default value {\tt Substitution}) is passed to internal @TO frobeniusRoot@ calls.

            When working in a $\mathbb{Q}$-Gorenstein ring $R$, {\tt testIdeal} looks for a positive integer $N$ such that $N K_R$ is Cartier.  
	    The option {\tt MaxCartierIndex} (default value $10$) controls the maximum value of $N$ to consider in this search.  
	    If the smallest such $N$ turns out to be greater than the value passed to {\tt MaxCartierIndex}, then {\tt testIdeal} returns an error.  

	    The $\mathbb{Q}$-Gorenstein index can be specified by the user through the option {\tt QGorensteinIndex}; when this option is used, the search for $N$ is bypassed, and the option {\tt MaxCartierIndex} ignored.
    SeeAlso
        testModule
        isFRegular
///



doc ///
    Key
        isFRegular
        (isFRegular, Ring)
        (isFRegular, Number, RingElement)
        (isFRegular, List, List)
        [isFRegular, AssumeDomain]
        [isFRegular, FrobeniusRootStrategy]
        [isFRegular, MaxCartierIndex]
        [isFRegular, QGorensteinIndex]
        [isFRegular, AtOrigin]
        [isFRegular, DepthOfSearch]
    Headline
        whether a ring or pair is strongly F-regular
    Usage
        isFRegular(R)
        isFRegular(t, f)
        isFRegular(tList, fList)
    Inputs
        R: Ring
        t: QQ
            a formal exponent for {\tt f}
        f: RingElement
            the element for the pair, to test $F$-regularity
        tList: List
            a list of formal exponents, for the elements of {\tt fList}
        fList: List
            a list of elements for a pair, to test $F$-regularity
        AssumeDomain => Boolean
            assumes the ring is an integral domain
        FrobeniusRootStrategy => Symbol
            selects the strategy for internal {\tt frobeniusRoot} calls
        MaxCartierIndex => ZZ
            sets the maximum Gorenstein index to search for when working with a $\mathbb{Q}$-Gorenstein ambient ring
        QGorensteinIndex => ZZ
            specifies the $\mathbb{Q}$-Gorenstein index of the ring
        AtOrigin => Boolean
            specifies whether to check $F$-regularity just at the origin
        DepthOfSearch => ZZ
            specifies how hard to try to prove that a non-$\mathbb{Q}$-Gorenstein ring is $F$-regular
    Outputs
        :Boolean
    Description
        Text
            Given a normal $\mathbb{Q}$-Gorenstein ring $R$, the function {\tt isFRegular} checks whether the ring is strongly $F$-regular.  
	    It can also prove that a non-$\mathbb{Q}$-Gorenstein ring is $F$-regular (but cannot show it is not); see below for how to access this functionality.
        Example
            R = ZZ/5[x,y,z]/(x^2 + y*z);
            isFRegular(R)
        Example
            R = ZZ/7[x,y,z]/(x^3 + y^3 + z^3);
            isFRegular(R)
        Text
            The function {\tt isFRegular} can also test strong $F$-regularity of pairs.
        Example
            R = ZZ/5[x,y];
            f = y^2 - x^3;
            isFRegular(1/2, f)
            isFRegular(5/6, f)
            isFRegular(4/5, f)
            isFRegular(4/5 - 1/100000, f)
        Text
            When checking whether a ring or pair is strongly $F$-regular, the option {\tt AtOrigin} determines if this is to be checked at the origin or everywhere.
	    The default value for {\tt AtOrigin} is {\tt false}, which corresponds to checking $F$-regularity everywhere; setting {\tt AtOrigin => true}, $F$-regularity is checked only at the origin.
        Example
            R = ZZ/7[x,y,z]/((x - 1)^3 + (y + 1)^3 + z^3);
            isFRegular(R)
            isFRegular(R, AtOrigin => true)
            S = ZZ/13[x,y,z]/(x^3 + y^3 + z^3);
            isFRegular(S)
            isFRegular(S, AtOrigin => true)
        Text
            Here is an example of {\tt AtOrigin} behavior with a pair.
        Example
            R = ZZ/13[x,y];
            f = (y - 2)^2 - (x - 3)^3;
            isFRegular(5/6, f)
            isFRegular(5/6, f, AtOrigin => true)
            g = y^2 - x^3;
            isFRegular(5/6, g)
            isFRegular(5/6, g, AtOrigin => true)
        Text
            The option {\tt AssumeDomain} (default value {\tt false}) is used when finding a test element.  
	    The option {\tt FrobeniusRootStrategy} (default value {\tt Substitution}) is passed to internal @TO frobeniusRoot@ calls.

            When working in a $\mathbb{Q}$-Gorenstein ring $R$, {\tt isFRegular} looks for a positive integer $N$ such that $N K_R$ is Cartier.  
	    The option {\tt MaxCartierIndex} (default value $10$) controls the maximum value of $N$ to consider in this search.  
	    If the smallest such $N$ turns out to be greater than the value passed to {\tt MaxCartierIndex}, then {\tt testIdeal} returns an error.  

	    The $\mathbb{Q}$-Gorenstein index can be specified by the user through the option {\tt QGorensteinIndex}; when this option is used, the search for $N$ is bypassed, and the option {\tt MaxCartierIndex} ignored.
        Text
            The function {\tt isFRegular} can show that rings that are {\bf not} $\mathbb{Q}$-Gorenstein are $F$-regular (it cannot, however, show that such a ring is {\bf not} $F$-regular).  
	    To do this, set the option {\tt QGorensteinIndex => infinity}.  
	    One may also use the option {\tt DepthOfSearch} to increase the depth of search.
        Example
            S = ZZ/7[x,y,z,u,v,w];
            I = minors(2, matrix {{x, y, z}, {u, v, w}});
            debugLevel = 1;
            time isFRegular(S/I, QGorensteinIndex => infinity, DepthOfSearch => 1)
            time isFRegular(S/I, QGorensteinIndex => infinity, DepthOfSearch => 2)
            debugLevel = 0;
    SeeAlso
        testIdeal
        isFRational
///

doc ///
    Key
        isFPure
        (isFPure, Ring)
        (isFPure, Ideal)
        [isFPure, AtOrigin]
        [isFPure, FrobeniusRootStrategy]
    Headline
        whether a ring is F-pure
    Usage
        isFPure(R)
        isFPure(I)
    Inputs
        R: Ring
            whose $F$-purity is to be checked
        I: Ideal
            the defining ideal of the ring whose $F$-purity is to be checked
        AtOrigin => Boolean
            specifies whether the $F$-purity is to be checked only at the origin 
        FrobeniusRootStrategy => Symbol
            selects the strategy for internal {\tt frobeniusRoot} calls
    Outputs
        :Boolean
    Description
        Text
            Given a ring $R$, this function checks whether the ring is $F$-pure, using Fedder's criterion (by applying @TO frobeniusRoot@ to $I^{[p]} : I$, where $I$ is the defining ideal of $R$).
        Example
            R = ZZ/5[x,y,z]/(x^2 + y*z);
            isFPure(R)
            R = ZZ/7[x,y,z]/(x^3 + y^3 + z^3);
            isFPure(R)
            R = ZZ/5[x,y,z]/(x^3 + y^3 + z^3);
            isFPure(R)
        Text
            Alternatively, one may pass the defining ideal of a ring.
        Example
            S = ZZ/2[x,y,z];
            isFPure ideal(y^2 - x^3)
            isFPure ideal(z^2 - x*y*z + x*y^2 + x^2*y)
        Text
            The option {\tt AtOrigin} controls whether $F$-purity is checked at the origin or everywhere.  
	    If its value is set to {\tt true} (the default is {\tt false}), it will only check $F$-purity at the origin.
        Example
            R = ZZ/5[x,y,z]/((x - 1)^3 + (y - 2)^3 + z^3);
            isFPure(R)
            isFPure(R, AtOrigin => true)
            S = ZZ/13[x,y,z]/(x^3 + y^3 + z^3);
            isFPure(S)
            isFPure(S, AtOrigin => true)
        Text
            Note that there is a difference in the strategy for the local or non-local computations. 
	    In fact, checking $F$-purity globally can sometimes be faster than checking it only at the origin.  
	    If {\tt AtOrigin} is set to {\tt false}, then {\tt isFPure} computes the @TO frobeniusRoot@ of $I^{[p]} : I$, whereas if {\tt AtOrigin} is set to {\tt true}, it checks whether $I^{[p]} : I$ is contained in $m^{[p]}$, where $m$ is the maximal ideal generated by the variables.
        Text
            The option {\tt FrobeniusRootStrategy} is passed to internal @TO frobeniusRoot@ calls, and specifies the strategy to be used.
    SeeAlso
        isFRegular
        isFInjective
///
