Example #1
0
    def find_bounding_cycle(self, G, npow=1):
        r'''
        Use recursively that:
        - x^a g = a x + g - del(x^a|g) - del(x|(x + x^2 + ... + x^(a-1)))
        - x^(-a) g = -a x + g + del(1|1) + del(x^(a)|(x^-a)) - del(x^(-a)|g) + del(x|(x + x^2 + ... + x^(a-1)))
        '''
        B = G.Gn.B
        gprimeq = self.quaternion_rep
        gprime = G.Gn(gprimeq)
        gword = tietze_to_syllables(gprime.word_rep)
        rels = G.Gn._calculate_relation(G.Gn.get_weight_vector(gprime**npow),
                                        separated=True)
        # If npow > 1 then add the boundary relating self^npow with npow*self
        ans = [(-1, [gprimeq**j
                     for j in range(1, npow)], gprime)] if npow > 1 else []

        num_terms = len(gword)
        jj = 0
        for i, a in gword:
            jj += 1
            # Decompose gword as g^a*gprime, where g is a generator
            g = G.Gn.gen(i)
            gq = g.quaternion_rep
            gaq = gq**a
            ga = g**a
            # Add the boundary relating g^a*gprime with g^a + gprime (unless we are in the last step)
            ans.extend([(-npow, [gaq],
                         G.Gn(gword[jj:]))] if jj < num_terms else [])
            # If a < 0 use the relation g^a = -g^(-a) + del(g^a|g^(-a))
            ans.extend([(npow, [gaq**-1], ga)] if a < 0 else [])
            # By the above line we have to deal with g^a with -g^abs(a) if a <0
            # We add the corresponding boundaries, which we will substract if a > 0 and add if a < 0
            ans.extend([(-sgn(a) * npow, [gq**j for j in range(1, abs(a))],
                         g)] if abs(a) > 1 else [])
        for m, rel in rels:
            # we deal with the relation rel^m
            # it is equivalent to deal with m*rel, because these two differ by a boundary that integrates to 1
            assert m > 0
            num_terms = len(rel)
            jj = 0
            for i, a in rel:
                jj += 1
                # we deal with a part of the relation of the form g*g'
                g = G.Gn.gen(i)
                gq = g.quaternion_rep
                ga = g**a
                gaq = gq**a
                # add the boundary relating g and g'
                ans.extend([(-m, [gaq],
                             G.Gn(rel[jj:]))] if jj < num_terms else [])
                # If a < 0 use the relation g^a = -g^(-a) + del(g^a|g^(-a))
                ans.extend([(m, [gaq**-1], ga)] if a < 0 else [])
                # add the boundaries of g^abs(a)
                ans.extend([(-sgn(a) * m, [gq**j for j in range(1, abs(a))],
                             g)] if abs(a) > 1 else [])
        return ans
Example #2
0
    def octants(self):
        assert self._degrees.is_finite()
        from sage.combinat.posets.posets import Poset

        def pocom(a, b):
            t1, e1, s1 = a
            t2, e2, s2 = b
            if (t1 in (t2, 0)) and (e1 in (e2, 0)) and (s1 in (s2, 0)):
                return True
            return False

        X = Poset(([(sgn(t), sgn(e), sgn(s)) for (t, e, s) in self._degrees], pocom))
        return [list(u) for u in X.maximal_elements()]
Example #3
0
    def neighbor(self, pt, d):
        r"""
        Return the neighbors of the point pt in direction d.

        INPUT:

        - ``pt`` - tuple, point in Z^d
        - ``direction`` - integer, possible values are 1, 2, ..., d and -1,
          -2, ..., -d.

        EXAMPLES:

            sage: from slabbe import BondPercolationSample
            sage: S = BondPercolationSample(0.5,2)
            sage: S.neighbor((2,3),1)
            (3, 3)
            sage: S.neighbor((2,3),2)
            (2, 4)
            sage: S.neighbor((2,3),-1)
            (1, 3)
            sage: S.neighbor((2,3),-2)
            (2, 2)

        """
        R = xrange(self._dimension)
        a = sgn(d)
        d = abs(d)
        return tuple(pt[k]+a if k==d-1 else pt[k] for k in R)
Example #4
0
    def neighbor(self, pt, d):
        r"""
        Return the neighbors of the point pt in direction d.

        INPUT:

        - ``pt`` - tuple, point in Z^d
        - ``direction`` - integer, possible values are 1, 2, ..., d and -1,
          -2, ..., -d.

        EXAMPLES:

            sage: from slabbe import BondPercolationSample
            sage: S = BondPercolationSample(0.5,2)
            sage: S.neighbor((2,3),1)
            (3, 3)
            sage: S.neighbor((2,3),2)
            (2, 4)
            sage: S.neighbor((2,3),-1)
            (1, 3)
            sage: S.neighbor((2,3),-2)
            (2, 2)

        """
        R = xrange(self._dimension)
        a = sgn(d)
        d = abs(d)
        return tuple(pt[k] + a if k == d - 1 else pt[k] for k in R)
Example #5
0
def polygon_compare(poly1,poly2):
    r"""
    Compare two polygons first by area, then by number of sides,
    then by lexigraphical ording on edge vectors."""
    from sage.functions.generalized import sgn
    res = int(sgn(-poly1.area()+poly2.area()))
    if res!=0:
        return res
    res = int(sgn(poly1.num_edges()-poly2.num_edges()))
    if res!=0:
        return res
    ne=poly1.num_edges()
    for i in range(0,ne-1):
        edge_diff = poly1.edge(i) - poly2.edge(i)
        res = int(sgn(edge_diff[0]))
        if res!=0:
            return res
        res = int(sgn(edge_diff[1]))
        if res!=0:
            return res
    return 0
Example #6
0
    def _test_generator_degrees(self, tester=None, **options):
        from sage.misc.sage_unittest import TestSuite
        from itertools import islice

        is_sub_testsuite = tester is not None
        tester = self._tester(tester=tester, **options)
        if self._is_sorted_by_t_degrees():
            gdegs = [g[0] for g in islice(self._degrees, 30)]
            gd = gdegs
            for u in gd:
                if u < 0:
                    gd = [-u for u in gdegs]
                    break
            for (u, v) in zip(gd, gd[1:]):
                tester.assertTrue(
                    u <= v,
                    LazyFormat(
                        "generators not sorted by internal degree, degrees= %s..."
                    )
                    % (gdegs,),
                )
        octs = self.octants()
        for (t, e, s) in islice(self._degrees, 30):
            if 0 != (e & 1):
                # allow mismatch for exterior generators
                continue
            ok = False
            for (ts, es, ss) in octs:
                if (sgn(t) in (ts, 0)) and (sgn(e) in (es, 0)) and (sgn(s) in (ss, 0)):
                    ok = True
                    break
            tester.assertTrue(
                ok,
                LazyFormat("generator degree (%d,%d,%d) not in one of the octants %s")
                % (t, e, s, octs),
            )
Example #7
0
def gamma_list_to_cyclotomic(galist):
    r"""
    Convert a quotient of products of polynomials `x^n - 1`
    to a quotient of products of cyclotomic polynomials.

    INPUT:

    - ``galist`` -- a list of integers, where an integer `n` represents
      the power `(x^{|n|} - 1)^{\operatorname{sgn}(n)}`

    OUTPUT:

    a pair of list of integers, where `k` represents the cyclotomic
    polynomial `\Phi_k`

    EXAMPLES::

        sage: from sage.modular.hypergeometric_motive import gamma_list_to_cyclotomic
        sage: gamma_list_to_cyclotomic([-1, -1, 2])
        ([2], [1])

        sage: gamma_list_to_cyclotomic([-1, -1, -1, -3, 6])
        ([2, 6], [1, 1, 1])

        sage: gamma_list_to_cyclotomic([-1, 2, 3, -4])
        ([3], [4])

        sage: gamma_list_to_cyclotomic([8,2,2,2,-6,-4,-3,-1])
        ([2, 2, 8], [3, 3, 6])
    """
    resu = defaultdict(int)
    for n in galist:
        eps = sgn(n)
        for d in divisors(abs(n)):
            resu[d] += eps

    return (sorted(d for d in resu for k in range(resu[d])),
            sorted(d for d in resu for k in range(-resu[d])))
def gamma_list_to_cyclotomic(galist):
    r"""
    Convert a quotient of products of polynomials `x^n - 1`
    to a quotient of products of cyclotomic polynomials.

    INPUT:

    - ``galist`` -- a list of integers, where an integer `n` represents
      the power `(x^{|n|} - 1)^{\operatorname{sgn}(n)}`

    OUTPUT:

    a pair of list of integers, where `k` represents the cyclotomic
    polynomial `\Phi_k`

    EXAMPLES::

        sage: from sage.modular.hypergeometric_motive import gamma_list_to_cyclotomic
        sage: gamma_list_to_cyclotomic([-1, -1, 2])
        ([2], [1])

        sage: gamma_list_to_cyclotomic([-1, -1, -1, -3, 6])
        ([2, 6], [1, 1, 1])

        sage: gamma_list_to_cyclotomic([-1, 2, 3, -4])
        ([3], [4])

        sage: gamma_list_to_cyclotomic([8,2,2,2,-6,-4,-3,-1])
        ([2, 2, 8], [3, 3, 6])
    """
    resu = defaultdict(int)
    for n in galist:
        eps = sgn(n)
        for d in divisors(abs(n)):
            resu[d] += eps

    return (sorted(d for d in resu for k in range(resu[d])),
            sorted(d for d in resu for k in range(-resu[d])))
Example #9
0
    def gamma_list(self):
        r"""
        Return a list of integers describing the `x^n - 1` factors.

        Each integer `n` stands for `(x^{|n|} - 1)^{\operatorname{sgn}(n)}`.

        EXAMPLES::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: Hyp(alpha_beta=([1/2],[0])).gamma_list()
            [-1, -1, 2]

            sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_list()
            [-1, -1, -1, -3, 6]

            sage: Hyp(cyclotomic=([3],[4])).gamma_list()
            [-1, 2, 3, -4]
        """
        gamma = self.gamma_array()
        resu = []
        for v, n in sorted(gamma.items()):
            resu += [sgn(n) * v] * abs(n)
        return resu
    def gamma_list(self):
        r"""
        Return a list of integers describing the `x^n - 1` factors.

        Each integer `n` stands for `(x^{|n|} - 1)^{\operatorname{sgn}(n)}`.

        EXAMPLES::

            sage: from sage.modular.hypergeometric_motive import HypergeometricData as Hyp
            sage: Hyp(alpha_beta=([1/2],[0])).gamma_list()
            [-1, -1, 2]

            sage: Hyp(cyclotomic=([6,2],[1,1,1])).gamma_list()
            [-1, -1, -1, -3, 6]

            sage: Hyp(cyclotomic=([3],[4])).gamma_list()
            [-1, 2, 3, -4]
        """
        gamma = self.gamma_array()
        resu = []
        for v, n in gamma.items():
            resu += [sgn(n) * v] * abs(n)
        return resu
def spin_weighted_spheroidal_harmonic(s,
                                      l,
                                      m,
                                      gamma,
                                      theta,
                                      phi,
                                      verbose=False,
                                      cached=True,
                                      min_nmax=8):
    r"""
    Return the spin-weighted oblate spheroidal harmonic of spin weight ``s``,
    degree ``l``, azimuthal order ``m`` and spheroidicity ``gamma``.

    INPUT:

    - ``s`` -- integer; the spin weight
    - ``l`` -- non-negative integer; the harmonic degree
    - ``m`` -- integer within the range ``[-l, l]``; the azimuthal number
    - ``gamma`` -- spheroidicity parameter
    - ``theta`` -- colatitude angle
    - ``phi`` -- azimuthal angle
    - ``verbose`` -- (default: ``False``) determines whether some details of
      the computation are printed out
    - ``cached`` -- (default: ``True``) determines whether the eigenvectors
      shall be cached; setting ``cached`` to ``False`` forces a new
      computation, without caching the result
    - ``min_nmax`` -- (default: 8) integer; floor for the evaluation of the
      parameter ``nmax``, which sets the highest degree of the spherical
      harmonic expansion as ``l+nmax``.

    OUTPUT:

    - value of `{}_s S_{lm}^\gamma(\theta,\phi)`

    ALGORITHM:

    The spin-weighted oblate spheroidal harmonics are computed by an expansion
    over spin-weighted *spherical* harmonics, the coefficients of the expansion
    being obtained by solving an eigenvalue problem, as exposed in Appendix A
    of S.A. Hughes, Phys. Rev. D **61**, 084004 (2000)
    [:doi:`10.1103/PhysRevD.61.084004`].

    EXAMPLES::

        sage: from kerrgeodesic_gw import spin_weighted_spheroidal_harmonic
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/2, 0)  # tol 1.0e-13
        0.08702532727529422
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/3, pi/3)  # tol 1.0e-13
        -0.14707166027821453 + 0.25473558795537715*I
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/3, pi/3, cached=False)   # tol 1.0e-13
        -0.14707166027821453 + 0.25473558795537715*I
        sage: spin_weighted_spheroidal_harmonic(-2, 2, 2, 1.1, pi/3, pi/4)  # tol 1.0e-13
        1.801108380050024e-17 + 0.2941433205564291*I
        sage: spin_weighted_spheroidal_harmonic(-2, 2, -1, 1.1, pi/3, pi/3, cached=False)  # tol 1.0e-13
        0.11612826056899399 - 0.20114004750009495*I

    Test that the relation
    `{}_s S_{lm}^\gamma(\theta,\phi) = (-1)^{l+s}\, {}_s S_{l,-m}^{-\gamma}(\pi-\theta,-\phi)`
    [cf. Eq. (2.3) of :arxiv:`1810.00432`], which is used to evaluate
    `{}_s S_{lm}^\gamma(\theta,\phi)` when `m<0` and ``cached`` is ``True``,
    is correctly implemented::

        sage: spin_weighted_spheroidal_harmonic(-2, 2, -2, 1.1, pi/3, pi/3)  # tol 1.0e-13
        -0.04097260436590737 - 0.07096663248016997*I
        sage: abs(_ - spin_weighted_spheroidal_harmonic(-2, 2, -2, 1.1, pi/3, pi/3,
        ....:                                           cached=False)) < 1.e-13
        True
        sage: spin_weighted_spheroidal_harmonic(-2, 3, -1, 1.1, pi/3, pi/3)  # tol 1.0e-13
        0.1781880511506843 - 0.3086307578946672*I
        sage: abs(_ - spin_weighted_spheroidal_harmonic(-2, 3, -1, 1.1, pi/3, pi/3,
        ....:                                           cached=False)) < 1.e-13
        True

    """
    global _eigenvectors
    if m < 0 and cached:
        # We use the symmetry formula
        #  {}_s S_{lm}^\gamma(\theta,\phi) =
        #                  (-1)^{l+s} {}_s S_{l,-m}^{-\gamma}(\pi-\theta,-\phi)
        # cf. Eq. (2.3) of  https://arxiv.org/abs/1810.00432
        return (-1)**(l + s) * spin_weighted_spheroidal_harmonic(
            s,
            l,
            -m,
            -gamma,
            pi - theta,
            -phi,
            verbose=verbose,
            cached=cached,
            min_nmax=min_nmax)
    s = ZZ(s)  # ensure that we are dealing with Sage integers
    l = ZZ(l)
    m = ZZ(m)
    gamma = RDF(gamma)  # all computations are performed with RDF
    param = (s, l, m, gamma)
    if cached:
        if param not in _eigenvectors:
            _eigenvectors[param] = _compute_eigenvector(*param,
                                                        verbose=verbose,
                                                        min_nmax=min_nmax)
        data = _eigenvectors[param]
    else:
        data = _compute_eigenvector(*param, verbose=verbose, min_nmax=min_nmax)
    egvec = data[1]
    nmin = data[2]
    nmax = data[3]
    lmin = data[4]
    # If neither theta nor phi is symbolic, we convert both of them to RDF:
    if not ((isinstance(theta, Expression) and theta.variables()) or
            (isinstance(phi, Expression) and phi.variables())):
        theta = RDF(theta)
        phi = RDF(phi)
    resu = RDF(0)
    for k in range(-nmin, nmax + 1):
        resu += egvec[k + nmin] \
                 * spin_weighted_spherical_harmonic(s, l+k, m, theta, phi,
                                                    condon_shortley=True)
    resu *= sgn(egvec[min(l - lmin + 1, (nmax + nmin) / 2 + 1) - 1])
    return resu