Ask Your Question
1

latex printing of polynomials

asked 2018-03-13 10:29:28 +0200

joaoff gravatar image

I have a code that generates some symbolic polynomials. I would like to generate the latex code for this polynomials to present them in the form: $ a_n \ s^n + a_{n-1} \ s^{n-1} + ... + a_1 \ s + a_0 $, where the coefficients $ a_n, ..., a_0 $ can be Real or Complex. The snippet below shows how I accomplish this.

var("s")
polynomial(s) = 115109024454248/712169248941107*(8*s^4 + 8*s^2 + 1)/pi - 1406886797940560/2486758794631057*(2*s^2 + 1)/pi + 59613932955136480/18544180962144109/pi
type(polynomial(s))
type(polynomial(s).polynomial(RR))
latex(polynomial(s).polynomial(RR))
# type(polynomial(s).polynomial(CC))
# latex(polynomial(s).polynomial(CC))

polynomial2(s) = 0.411591379742810*s^4 + 0.000000000000000*s^3 + 0.0514229729855488*s^2 + 0.000000000000000*s + 0.894634727759564
type(polynomial2(s))
latex(polynomial2(s))

the code outputs

s
<type 'sage.symbolic.expression.Expression'>
<type 'sage.rings.polynomial.polynomial_real_mpfr_dense.PolynomialRealDense'>
0.411591379742810 s^{4} + 0.000000000000000 s^{3} + 0.0514229729855488 s^{2} + 0.000000000000000 s + 0.894634727759564
<type 'sage.symbolic.expression.Expression'>
0.411591379742810 \, s^{4} + 0.0514229729855488 \, s^{2} + 0.894634727759564

Now, the questions are:

1) Is printing polynomials terms with zero coefficients the intended behavior for the _latex()_ command when operating over type 'sage.rings.polynomial.polynomial_real_mpfr_dense.PolynomialRealDense' and class 'sage.rings.polynomial.polynomial_ring.PolynomialRing_field_with_category.element_class'? the _latex()_ command behaves differently when operating over symbolic polynomials.

2) Is there a way to set the displayed number of digits?

3) Is there a better way to present such symbolic polynomials in latex code in the desired format?

Cordially

edit retag flag offensive close merge delete

Comments

1

1) Yes.

Does the following help

sage: R.<s> = QQ[]
sage: P = s^5+s+1
sage: latex(P)
s^{5} + s + 1
sage: latex(P.change_ring(RR))
s^{5} + 0.000000000000000 s^{4} + 0.000000000000000 s^{3} + 0.000000000000000 s^{2} + s + 1.00000000000000
sage: latex(P.change_ring(RealField(10)))
s^{5} + 0.00 s^{4} + 0.00 s^{3} + 0.00 s^{2} + s + 1.0
sage: latex(P.change_ring(RealField(20)))
s^{5} + 0.00000 s^{4} + 0.00000 s^{3} + 0.00000 s^{2} + s + 1.0000

(The zero is shown, the one is not...)

(2) The precision of the real field did it above.

(3) Depends on the needs, Since we can access the coefficients and the powers of the monomials, we can print our own way, e.g. using a custom function. (Then python could format via %f or %g or %e the coefficients.)

dan_fulea gravatar imagedan_fulea ( 2018-03-14 01:09:04 +0200 )edit

I have two new questions:

1) Why the latex function when operating on ring types/classes behaves differently, printing zeroed terms, then when operating on symbolic types, when it does not print the zeroed terms?

2) Considering the example below, based on my answer, I was expecting, for example, that the numerical approximation of the term of order zero (0.36199913930075) would be returned as 0.362, but the value returned was 0.3617. Why the slight difference?

print(print_poly(e, 14, 10^-10))
print(print_poly(e, 4, 10^-10))

Output

s^6 + 2.5234940770578*s^5 + 4.5714914424575*s^4 + 4.9509592139705*s^3 + 3.7020907647966*s^2 + 1.6452145832311*s + 0.36199913930075
s^6 + 2.522*s^5 + 4.569*s^4 + 4.947*s^3 + 3.699*s^2 + 1.644*s + 0.3617

Thank you!

joaoff gravatar imagejoaoff ( 2018-03-14 15:04:27 +0200 )edit
1

(1) latex is different from type to type, as one should expect. Try latex?? to see how ramified it is the work delegated to subroutines.

(2) The error may be understood from the following:

sage: c = e.coefficients()[0][0]
sage: x4 = c.n(digits=4)
sage: x4
0.3617
sage: x4 == 0.3617
False
sage: x4.str( base=2 )
'0.010111001001100101'
sage: (0.3617).str( base=2 )
'0.010111001001100001011111000001101111011010010100010010'

where e is as in the answer. See also ??N, where

    sage: x=N(pi, digits=3); x
    3.14
    sage: y=N(3.14, digits=3); y
    3.14
    sage: x==y
    False
    sage: x.str(base=2)
    '11.001001000100'
    sage: y.str(base=2)
    '11.001000111101'

is an other example.

dan_fulea gravatar imagedan_fulea ( 2018-03-15 04:55:03 +0200 )edit

1 Answer

Sort by ยป oldest newest most voted
1

answered 2018-03-14 14:42:21 +0200

joaoff gravatar image

updated 2018-03-14 14:52:11 +0200

Thank you, @dan_fulea!

I ended by taking a different approach. I created two functions, one for cropping the real and/or imaginary parts that are below a threshold, as the Mathematica function, and another that apply this crop function to generate a new polynomial with coefficients approximated to a specified number of digits. This function also converts the real numbers with zero fractional part (e.g. 1.0000) to the equivalent integer, so that the coefficient of any term that is exactly 1, do not show.

e = 1/46656*(9*(36*s^2 - 3*(6*s + 1/tan(55/72))/(2/tan(14/9) - 1/tan(55/72)) + 1)*(4*s^2 + 1) - 7*(4*(9*s^2 + 1)*(6*s + 1/tan(55/72)) + 5*(36*s^2 - 3*(6*s + 1/tan(55/72))/(2/tan(14/9) - 1/tan(55/72)) + 1)/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72))))/(4/(5/(4/tan(29/9) - 1/tan(55/72)) - 1/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72)))))*(36*s^2 + 25) - 11/46656*(4*(4*(9*s^2 + 1)*(6*s + 1/tan(55/72)) + 5*(36*s^2 - 3*(6*s + 1/tan(55/72))/(2/tan(14/9) - 1/tan(55/72)) + 1)/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72))))*(9*s^2 + 4) + 9*(9*(36*s^2 - 3*(6*s + 1/tan(55/72))/(2/tan(14/9) - 1/tan(55/72)) + 1)*(4*s^2 + 1) - 7*(4*(9*s^2 + 1)*(6*s + 1/tan(55/72)) + 5*(36*s^2 - 3*(6*s + 1/tan(55/72))/(2/tan(14/9) - 1/tan(55/72)) + 1)/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72))))/(4/(5/(4/tan(29/9) - 1/tan(55/72)) - 1/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72)))))/(16/(7/(8/(5/tan(295/72) - 1/tan(55/72)) - 1/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72)))) - 7/(4/(5/(4/tan(29/9) - 1/tan(55/72)) - 1/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72))))))/(20/(27/(32/(35/(6/tan(5) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72)))) - 7/(4/(5/(4/tan(29/9) - 1/tan(55/72)) - 1/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72))))) - 9/(16/(7/(8/(5/tan(295/72) - 1/tan(55/72)) - 1/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72)))) - 7/(4/(5/(4/tan(29/9) - 1/tan(55/72)) - 1/(2/tan(14/9) - 1/tan(55/72))) - 5/(8/(3/tan(19/8) - 1/tan(55/72)) - 3/(2/tan(14/9) - 1/tan(55/72))))))
f = (s + 0.267263403945694 + 0.717946300381457*I)*(s + 0.267263403945694 - 0.717946300381457*I)*(s + 0.0662957565747883 + 0.945082838443603*I)*(s + 0.0662957565747883 - 0.945082838443603*I)*(s + 1.58872258534575e-15 + 0.323790242740243*I)*(s + 1.58872258534575e-15 - 0.323790242740243*I)
p = -481858107122483/34956364583988030*(32*s^6 + 48*s^4 + 18*s^2 + 1)/pi + 421794849676389/2806321699992460*(8*s^4 + 8*s^2 + 1)/pi - 3217349902914616/4621771216286985*(2*s^2 + 1)/pi + 732820056818024/435368484578163/pi

def crop(CC_value, RR_threshold):
    if abs(CC_value.real()) > RR_threshold and abs(CC_value.imag()) > RR_threshold:
        return CC_value
    elif abs(CC_value.real()) > RR_threshold and abs(CC_value.imag()) < RR_threshold:
        return CC_value.real()
    elif abs(CC_value.real()) < RR_threshold and abs(CC_value.imag()) > RR_threshold:
        return CC_value.imag()*i
    else:
        return 0

def print_poly(SymbolicExpression_poly, ZZ_digits, RR_threshold):
    coeff = []
    for coefficient in SymbolicExpression_poly.coefficients():
        coeff.append((Integer(int(coefficient[0])),coefficient[1]) if frac(coefficient[0]) == 0 else (__crop(coefficient[0].n(digits=ZZ_digits),RR_threshold),coefficient[1]))
    return sum([a*s^b for a,b in coeff])

print(print_poly(e, 3, 10^-10))
print(print_poly(f, 4, 10^-10))
print(print_poly(p, 5, 10^-10))

The output is

s^6 + 2.54*s^5 + 4.59*s^4 + 4.98*s^3 + 3.73*s^2 + 1.66*s + 0.364
s^6 + 0.6671*s^5 + 1.660*s^4 + 0.6275*s^3 + 0.6898*s^2 + 0.05846*s + 0.05523
-0.14041*s^6 + 0.17213*s^4 - 0.13941*s^2 + 0.35765

Surely the code is not optimized and may contain errors, but it worked fine in my tests. So, I will accept my own answer :-/.

edit flag offensive delete link more

Comments

You should actually accept your own answer by clicking the "accept" button near the top of the answer.

slelievre gravatar imageslelievre ( 2018-03-16 18:03:24 +0200 )edit

I have accepted it now. I hadn't done it before because I hadn't sufficient "karma" points.

joaoff gravatar imagejoaoff ( 2018-03-16 18:13:50 +0200 )edit

Your Answer

Please start posting anonymously - your entry will be published after you log in or create a new account.

Add Answer

Question Tools

1 follower

Stats

Asked: 2018-03-13 10:29:28 +0200

Seen: 837 times

Last updated: Mar 14 '18