-
Notifications
You must be signed in to change notification settings - Fork 30
/
Copy pathshow.jl
205 lines (188 loc) · 6.46 KB
/
show.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
const TypesWithShow = Union{
AbstractVariable,
AbstractMonomial,
AbstractTerm,
AbstractPolynomial,
RationalPoly,
}
function Base.show(io::IO, mime::MIME"text/latex", p::TypesWithShow)
print(io, "\$\$ ")
_show(io, mime, p)
return print(io, " \$\$")
end
# If the MIME is not specified, IJulia thinks that it supports images, ...
# and then use the result of show and tries to interpret it as an svg, ...
# We need the two methods to avoid ambiguity
function Base.show(io::IO, mime::MIME"text/plain", p::TypesWithShow)
return _show(io, mime, p)
end
function Base.show(io::IO, mime::MIME"text/print", p::TypesWithShow)
return _show(io, mime, p)
end
Base.print(io::IO, p::TypesWithShow) = show(io, MIME"text/print"(), p)
Base.show(io::IO, p::TypesWithShow) = show(io, MIME"text/plain"(), p)
# VARIABLES
function _show(io::IO, mime::MIME, var::AbstractVariable)
base, indices = name_base_indices(var)
if isconj(var)
for c in String(base)
print(io, c, '\u0305') # displays as overbar (̄z)
end
else
print(io, base)
end
if !isempty(indices)
print_subscript(io, mime, indices)
end
isrealpart(var) && print(io, "ᵣ") # suffixes for real and imaginary part: zᵣ, zᵢ
return isimagpart(var) && print(io, "ᵢ")
end
function print_subscript(io::IO, ::MIME"text/print", index)
return print(io, "[", join(index, ","), "]")
end
function print_subscript(io::IO, ::MIME"text/latex", index)
return print(io, "_{", join(index, ","), "}")
end
function print_subscript(io::IO, mime, indices)
if length(indices) == 1
print(io, unicode_subscript(indices[1]))
else
print(io, join(unicode_subscript.(indices), "\u208B"))
end
end
const unicode_subscripts = ("₀", "₁", "₂", "₃", "₄", "₅", "₆", "₇", "₈", "₉")
unicode_subscript(i) = join(unicode_subscripts[d+1] for d in reverse(digits(i)))
# MONOMIALS
function _show(io::IO, mime, m::AbstractMonomial)
if isconstant(m)
print(io, '1')
else
printed_var = false
vars = variables(m)
n = length(vars)
for (i, var, exp) in zip(1:n, vars, exponents(m))
if !iszero(exp)
if mime isa MIME"text/print" && printed_var && i > 0
print(io, "*")
end
_show(io, mime, var)
printed_var = true
if !isone(exp)
print_exponent(io, mime, exp)
end
end
end
end
end
print_exponent(io::IO, ::MIME"text/latex", exp) = print(io, "^{", exp, "}")
print_exponent(io::IO, ::MIME"text/print", exp) = print(io, "^", exp)
function print_exponent(io::IO, mime, exp)
return print(io, join(unicode_superscript.(reverse(digits(exp)))))
end
const unicode_superscripts = ("⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹")
unicode_superscript(i) = unicode_superscripts[i+1]
# TERM
function _show(io::IO, mime, t::AbstractTerm)
if isconstant(t)
print_coefficient(io, mime, coefficient(t))
else
if should_print_coefficient(coefficient(t))
if !should_print_coefficient(-coefficient(t))
print(io, '-')
else
print_coefficient(io, mime, coefficient(t))
if !iszero(t)
# Print a multiplication sign between coefficent and monmomial
# depending on the mime type
print_maybe_multiplication_sign(io, mime)
end
end
end
if !iszero(t)
_show(io, mime, monomial(t))
end
end
end
"""
print_maybe_multiplication_sign(io, mime)
Prints a multiplication sign depending on the `mime` type.
"""
print_maybe_multiplication_sign(io::IO, ::MIME"text/print") = print(io, "*")
print_maybe_multiplication_sign(io::IO, mime) = nothing
should_print_coefficient(x) = true # By default, just print all coefficients
should_print_coefficient(x::Number) = !isone(x) # For numbers, we omit any "one" coefficients
# `Int`, `Float64` don't support MIME"text/latex".
# We could add a check with `showable` if a `Real` subtype supports it and
# the feature is requested.
print_coefficient(io::IO, mime, coeff::Real) = print(io, coeff)
# Scientific notation does not display well in LaTeX so we rewrite it
function print_coefficient(io::IO, mime::MIME"text/latex", coeff::AbstractFloat)
s = string(coeff)
if occursin('e', s)
s = replace(s, 'e' => " \\cdot 10^{") * '}'
end
return print(io, s)
end
function _trim_LaTeX(s::AbstractString)
i = firstindex(s)
j = lastindex(s)
while true
if i < j && isspace(s[i])
i = nextind(s, i)
elseif i < j && isspace(s[j])
j = prevind(s, j)
elseif i < j && s[i] == '$' && s[j] == '$'
i = nextind(s, i)
j = prevind(s, j)
elseif i < j && (
(s[i:nextind(s, i)] == "\\(" && s[prevind(s, j):j] == "\\)") ||
(s[i:nextind(s, i)] == "\\[" && s[prevind(s, j):j] == "\\]")
)
i = nextind(s, i, 2)
j = prevind(s, j, 2)
else
return s[i:j]
end
end
end
# JuMP expressions supports LaTeX output so `showable` will return `true`
# for them. It is important for anonymous variables to display properly as well:
# https://github.com/jump-dev/SumOfSquares.jl/issues/256
# Since they add `$$` around it, we need to trim it with `_trim_LaTeX`
function print_coefficient(io::IO, mime, coeff)
print(io, "(")
if showable(mime, coeff)
print(io, _trim_LaTeX(sprint(show, mime, coeff)))
else
show(io, coeff)
end
return print(io, ")")
end
# POLYNOMIAL
function _show(io::IO, mime, p::AbstractPolynomial{T}) where {T}
ts = terms(p)
if isempty(ts)
print(io, zero(T))
else
_show(io, mime, first(ts))
for t in Iterators.drop(ts, 1)
if isnegative(coefficient(t))
print(io, " - ")
_show(io, mime, abs(coefficient(t)) * monomial(t))
else
print(io, " + ")
_show(io, mime, t)
end
end
end
end
isnegative(x::Real) = x < 0
isnegative(x) = false
# RATIONAL POLY
function _show(io::IO, mime, p::RationalPoly)
print(io, mime isa MIME"text/latex" ? "\\frac{" : "(")
_show(io, mime, p.num)
print(io, mime isa MIME"text/latex" ? "}{" : ") / (")
_show(io, mime, p.den)
return print(io, mime isa MIME"text/latex" ? "}" : ")")
end