Exemplo n.º 1
0
def alpha_to_cyclotomic(alpha):
    """
    Convert from a list of rationals arguments to a list of integers.

    The input represents arguments of some roots of unity.

    The output represent a product of cyclotomic polynomials with exactly
    the given roots. Note that the multiplicity of `r/s` in the list
    must be independent of `r`; otherwise, a ``ValueError`` will be raised.

    This is the inverse of :func:`cyclotomic_to_alpha`.

    EXAMPLES::

        sage: from sage.modular.hypergeometric_motive import alpha_to_cyclotomic
        sage: alpha_to_cyclotomic([0])
        [1]
        sage: alpha_to_cyclotomic([1/2])
        [2]
        sage: alpha_to_cyclotomic([1/5,2/5,3/5,4/5])
        [5]
        sage: alpha_to_cyclotomic([0, 1/6, 1/3, 1/2, 2/3, 5/6])
        [1, 2, 3, 6]
        sage: alpha_to_cyclotomic([1/3,2/3,1/2])
        [2, 3]
    """
    cyclo = []
    Alpha = list(alpha)
    while Alpha:
        q = QQ(Alpha.pop())
        n = q.numerator()
        d = q.denominator()
        for k in d.coprime_integers(d):
            if k != n:
                try:
                    Alpha.remove(QQ((k, d)))
                except ValueError:
                    raise ValueError("multiplicities not balanced")
        cyclo.append(d)
    return sorted(cyclo)
def alpha_to_cyclotomic(alpha):
    """
    Convert from a list of rationals arguments to a list of integers.

    The input represents arguments of some roots of unity.

    The output represent a product of cyclotomic polynomials with exactly
    the given roots. Note that the multiplicity of `r/s` in the list
    must be independent of `r`; otherwise, a ``ValueError`` will be raised.

    This is the inverse of :func:`cyclotomic_to_alpha`.

    EXAMPLES::

        sage: from sage.modular.hypergeometric_motive import alpha_to_cyclotomic
        sage: alpha_to_cyclotomic([0])
        [1]
        sage: alpha_to_cyclotomic([1/2])
        [2]
        sage: alpha_to_cyclotomic([1/5,2/5,3/5,4/5])
        [5]
        sage: alpha_to_cyclotomic([1/6, 1/3, 1/2, 2/3, 5/6, 1])
        [1, 2, 3, 6]
        sage: alpha_to_cyclotomic([1/3,2/3,1/2])
        [2, 3]
    """
    cyclo = []
    Alpha = list(alpha)
    while Alpha:
        q = QQ(Alpha.pop())
        n = q.numerator()
        d = q.denominator()
        for k in d.coprime_integers(d):
            if k != n:
                try:
                    Alpha.remove(QQ((k, d)))
                except ValueError:
                    raise ValueError("multiplicities not balanced")
        cyclo.append(d)
    return sorted(cyclo)
Exemplo n.º 3
0
class QQpApprox_element(RingElement,Approximation):  # maybe should create a ApproximatedRingElement
    def __init__(self,parent,x,val=0,normalized=False):
        RingElement.__init__(self,parent)
        Approximation.__init__(self,parent)
        self._x = QQ(x)
        self._val = val
        self._normalized = normalized

    def _normalize(self):
        if not self._normalized:
            if self._x == 0:
                self._val = 0
            else:
                powers = self.parent().uniformizer
                v = self._x.valuation(powers())
                self._val += v
                if v > 0:
                    self._x /= powers(v)
                elif v < 0:
                    self._x *= powers(-v)
            self._normalized = True

    def parenthesis_level(self):
        if self._x.denominator() == 1:
            return 3
        else:
            return 1

    def _getitem_by_num(self,i):
        return self

    def is_zero(self):
        return self._x == 0

    def _add_(self,other,**kwargs):
        parent = self.parent()
        selfval = self._val
        otherval = other._val
        if selfval == otherval:
            return QQpApprox_element(parent, self._x + other._x, selfval)
        if selfval > otherval:
            return QQpApprox_element(parent, self._x * parent.uniformizer(selfval-otherval) + other._x, otherval)
        else:
            return QQpApprox_element(self.parent(), self._x + other._x * parent.uniformizer(otherval-selfval), selfval)

    def __neg__(self,**kwargs):
        return QQpApprox_element(self.parent(), -self._x, self._val)

    def _sub_(self,other,**kwargs):
        parent = self.parent()
        selfval = self._val
        otherval = other._val
        if selfval == otherval:
            return QQpApprox_element(parent, self._x - other._x, selfval)
        if selfval > otherval:
            return QQpApprox_element(parent, self._x * parent.uniformizer(selfval-otherval) - other._x, otherval)
        else:
            return QQpApprox_element(self.parent(), self._x - other._x * parent.uniformizer(otherval-selfval), selfval)

    def _mul_(self,other,**kwargs):
        return QQpApprox_element(self.parent(), self._x * other._x, self._val + other._val, self._normalized and other._normalized)

    def _rmul_(self,other,**kwargs):
        return self._mul_(other,**kwargs)

    def _lmul_(self,other,**kwargs):
        return self._mul_(other,**kwargs)

    def __invert__(self,**kwargs):
        return QQpApprox_element(self.parent(), ~self._x, -self._val, self._normalized)

    def _div_(self,other,**kwargs):
        return QQpApprox_element(self.parent(), self._x / other._x, self._val - other._val, self._normalized and other._normalized)

    def valuation(self,lazylimit=Infinity):
        self._normalize()
        if self._x == 0:
            return Infinity
        else:
            return self._val

    def _repr_(self):
        self._normalize()
        if self._x == 0:
            return "0"
        elif self._val == 0:
            return "%s" % self._x
        else:
            return "%s*%s^%s" % (self._x, self.parent()._p, self._val)

    def __pow__(self,exp,**kwargs):
        return QQpApprox_element(self.parent(), self._x ** exp, self._val * exp, self._normalized)

    def __cmp__(self,other):
        v = self._val - other._val
        return cmp(self._x, other._x * self.parent().uniformizer(v))

    def truncate(self,workprec):
        if workprec == Infinity:
            return self
        parent = self.parent()
        self._normalize()
        pow = workprec - self._val
        if pow <= 0:
            return QQpApprox_element(parent, 0, 0, True)
        modulo = parent.uniformizer(pow)
        num = self._x.numerator() % modulo
        denom = self._x.denominator() % modulo
        if denom != 1:
            _,inv,_ = denom.xgcd(modulo)
            num = (num * inv) % modulo
        return QQpApprox_element(parent, num, self._val, True)

    def log(self,workprec=Infinity):
        from sage.functions.log import log
        from sage.functions.other import floor
        if workprec is Infinity:
            raise ApproximationError("unable to compute log to infinite precision")
        parent = self.parent()
        pow = parent(-1)
        res = parent(0)
        t = parent(1) - self
        iter = workprec + floor(log(workprec)/log(parent._p)) + 1
        for i in range(1,iter):
            pow *= t
            res += pow / parent(i)
            res = res.truncate(workprec)
        return res

    def exp(self,workprec=Infinity):
        from sage.functions.other import ceil
        if workprec is Infinity:
            raise ApproximationError("unable to compute exp to infinite precision")
        parent = self.parent()
        pow = parent(1)
        res = parent(1)
        val = self.valuation()
        iter = ceil(workprec / (val - 1/(parent._p-1))) + 1
        for i in range(1,iter):
            pow *= self / parent(i)
            res += pow
            res = res.truncate(workprec)
        return res

    def teichmuller(self,workprec=Infinity):
        if workprec is Infinity:
            raise ApproximationError("unable compute Teichmuller lift to infinite precision")
        res = self.truncate(1)
        p = self.parent()._p
        for i in range(2,workprec+1):
            res = res ** p
            res = res.truncate(i)
        return res