Hi,

The following example from q_analogues.py happens to work for a number 
of questionable reasons:

  sage: q_binomial(6,1,I)
  1 + I

I'm working on a patch that breaks (or fixes, depending how you look at 
it) one of the behaviors it relies on, and I'd like advice on how to 
handle the situation.

Here is my understanding of what is going on. Please correct me if I'm 
missing something.

The implementation of q_binomial(n, k, q) in this case essentially 
amounts to:

  from sage.rings.polynomial.cyclotomic import cyclotomic_value
  return prod(cyclotomic_value(d,q)
              for d in range(2,n+1)
              if floor(n/d) != floor(k/d) + floor((n-k)/d))

and that cyclotomic_value(n, x) to

    if n < 3:
        if n == 1:
            return x - 1
        if n == 2:
            return x + 1
        raise ValueError("n must be positive")
    try:
        return x.parent()(pari.polcyclo_eval(n, x))
    ...
 
Now recall that I is an element of SR that wraps an element of a 
quadratic number field equipped with a complex embedding:

  sage: I.parent()
  Symbolic Ring
  sage: I.pyobject().parent()
  Number Field in I with defining polynomial x^2 + 1
  sage: I.pyobject().parent().coerce_embedding()
  Generic morphism:
    From: Number Field in I with defining polynomial x^2 + 1
    To:   Complex Lazy Field
    Defn: I -> 1*I

At first cyclotomic_value() appears to work well when called with q=I:

  sage: cyclotomic_value(1, I)
  I - 1
  sage: cyclotomic_value(3, I)
  I

The call to polcyclo_eval() succeeds "thanks" to the fact that 
essentially anything can be converted (and even coerced) to a Pari 
object based, ultimately, on its string representation. (This happens 
through a maze of calls to _pari_, _pari_init_, _interface_init_, 
PariInstance.__call__ and objtogen. By the way, can anyone explain the 
interplay between the *two* places where the conversion falls back to 
using the string representation, namely in SageObject._interface_init_ 
and pari.gen.objtogen?)

As cyclotomic_value() is careful to convert back the result to the 
parent of x, we have:

  sage: cyclotomic_value(1, I).parent()
  Symbolic Ring
  sage: cyclotomic_value(3, I).parent()
  Symbolic Ring

But depending on the value of the first parameter, the true numeric 
object wrapped by the symbolic result will not have the same parent:

  sage: cyclotomic_value(1, I).pyobject().parent()
  Number Field in I with defining polynomial x^2 + 1
  sage: cyclotomic_value(3, I).pyobject().parent()
  Interface to the PARI C library

Not very nice, but hopefully the coercion system should be able to 
handle this, right? As it turns out, number fields have a properly 
implemented conversion to Pari (one that doesn't just take the string 
representation and hope for the best). This conversion, however, ignores 
the embedding:

  sage: pari(I.pyobject())
  Mod(y, y^2 + 1)

Thus:

  sage: pari(I)*pari(I.pyobject())
  Mod(I*y, y^2 + 1)

and yet:

  sage: pari(I)*I.pyobject()
  -1
  sage: (pari(I)*I.pyobject()).parent()
  Interface to the PARI C library

The trick is that the coercion discovery system currently prefers

  sage: pari.coerce_map_from(I.pyobject().parent())
  Composite map:
    From: Number Field in I with defining polynomial x^2 + 1
    To:   Interface to the PARI C library
    Defn:   Generic morphism:
            From: Number Field in I with defining polynomial x^2 + 1
            To:   Complex Lazy Field
            Defn: I -> 1*I
          then
            Call morphism:
            From: Complex Lazy Field
            To:   Interface to the PARI C library

to the direct conversion (which, as already mentioned, is also marked as 
a coercion). Of course, the coercion diagram is supposed to be 
commutative, but we all know this is currently far from true.

This indirect coercion has the benefit of taking the embedding into 
account, and turns out to give the correct result in our particular 
example. In general, however, it is much worse than the direct one. 
Indeed, the CLF -> pari step is the fall-back conversion based on the 
string representation:

  sage: pari(1)*(I.pyobject()/3)
    ***   Warning: unused characters: ?*I.
  0.333333333333333

Now to my questions. A side effect of the patches I'm working on at 
#14982 to fix another coercion problem is that the direct conversion 
NF -> pari would be preferred to the indirect one, leading to:

  sage: q_binomial(6,1,I)
  Mod(y + 1, y^2 + 1)

So:

(1) What would be an acceptable workaround for the regression in
    q_binomial() that would allow me to move forward with the ticket
    I was originally working on?

(2) In the longer term, how do we deal with that mess?

Thanks,

-- 
Marc

-- 
You received this message because you are subscribed to the Google Groups 
"sage-devel" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sage-devel+unsubscr...@googlegroups.com.
To post to this group, send email to sage-devel@googlegroups.com.
Visit this group at http://groups.google.com/group/sage-devel.
For more options, visit https://groups.google.com/d/optout.

Reply via email to