Skip to content

Commit

Permalink
Improve show (#44)
Browse files Browse the repository at this point in the history
* Improve show

* Add tests

* Fixes
  • Loading branch information
blegat authored Jun 13, 2024
1 parent c5cc1f4 commit 7550169
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 18 deletions.
108 changes: 94 additions & 14 deletions src/show.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,38 +3,118 @@ function Base.show(io::IO, A::AbstractStarAlgebra)
return print(ioc, "*-algebra of ", object(A))
end

__prints_with_minus(::Any) = false
__prints_with_minus(x::Real) = x < 0
__needs_parens(::Any) = false
__needs_parens(a::AlgebraElement) = true

function _coeff_elt_print(io, c, elt)
print(io, c, '·')
# `print_coefficient` is inspired from MultivariatePolynomials.jl

# `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"text/latex", coeff::AbstractFloat)
s = string(coeff)
if occursin('e', s)
s = replace(s, 'e' => " \\cdot 10^{") * '}'
end
return print(io, s)
end

trim_LaTeX(_, s::AbstractString) = s

function trim_LaTeX(::MIME"text/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, "(")
print_mime(io, mime, coeff)
print(io, ")")
return
end

function print_mime(io::IO, mime, x)
if showable(mime, x)
print(io, trim_LaTeX(mime, sprint(show, mime, x)))
else
show(io, x)
end
end

isnegative(x::Real) = x < 0
isnegative(x) = false

_print_dot(io, ::MIME"text/latex") = print(io, " \\cdot ")
_print_dot(io, ::MIME) = print(io, '·')

function _coeff_elt_print(io, mime, c, elt)
print_coefficient(io, mime, c)
_print_dot(io, mime)
__needs_parens(elt) && print(io, '(')
print(io, elt)
print_mime(io, mime, elt)
__needs_parens(elt) && print(io, ')')
return
end

function Base.show(io::IO, a::AlgebraElement)
Base.print(io::IO, a::AlgebraElement) = show(io, MIME"text/print"(), a)
Base.show(io::IO, a::AlgebraElement) = show(io, MIME"text/plain"(), a)

function Base.show(io::IO, mime::MIME"text/latex", a::AlgebraElement)
print(io, "\$\$ ")
_show(io, mime, a)
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", a::AlgebraElement)
return _show(io, mime, a)
end
function Base.show(io::IO, mime::MIME"text/print", a::AlgebraElement)
return _show(io, mime, a)
end

function _show(io::IO, mime, a::AlgebraElement)
A = parent(a)
if iszero(a)
T = valtype(coeffs(a))
_coeff_elt_print(io, zero(T), first(basis(A)))
_coeff_elt_print(io, mime, zero(T), first(basis(A)))
else
_first = true
for (idx, value) in nonzero_pairs(coeffs(a))
c, elt = value, basis(A)[idx]
if _first
_coeff_elt_print(io, c, elt)
_coeff_elt_print(io, mime, c, elt)
_first = false
else
if __prints_with_minus(c)
print(io, ' ')
else
print(io, ' ', '+')
end
_coeff_elt_print(io, c, elt)
neg = isnegative(c)
print(io, ' ', neg ? '-' : '+', ' ')
_coeff_elt_print(io, mime, neg ? abs(c) : c, elt)
end
end
end
Expand Down
33 changes: 29 additions & 4 deletions test/constructors.jl
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
struct CustomLaTeXPrint
s::String
end

Base.:-(s::CustomLaTeXPrint) = s
Base.iszero(::CustomLaTeXPrint) = false
function Base.show(io::IO, ::MIME"text/latex", s::CustomLaTeXPrint)
return print(io, s.s)
end

@testset "Algebra and Elements" begin
alph = [:a, :b, :c]
A★ = FreeWords(alph)
Expand Down Expand Up @@ -74,12 +84,17 @@
# @test SA.supp_ind(aa) == [b[s]] == SA.supp_ind(dense_aa)
@test SA.supp(aa) == [s]

@test sprint(show, a) == "2·(id) +1·b·c"
@test sprint(show, -a) == "-2·(id) -1·b·c"
@test sprint(show, a) == "2·(id) + 1·b·c"
@test sprint(show, -a) == "-2·(id) - 1·b·c"
Z = AlgebraElement{Float64}(a)
@test Z == a
@test sprint(show, Z) == "2.0·(id) +1.0·b·c"
@test sprint(show, 2one(RG) - RG(p)) == "2·(id) -1·b·c"
@test sprint(show, Z) == "2.0·(id) + 1.0·b·c"
@test sprint(show, 2one(RG) - RG(p)) == "2·(id) - 1·b·c"
@test sprint(show, (2 + im) * one(RG) - (3im) * RG(p)) == "(2 + 1im)·(id) + (0 - 3im)·b·c"

@test sprint(print, (2 + im) * one(RG) - (3im) * RG(p)) == "(2 + 1im)·(id) + (0 - 3im)·b·c"
@test sprint(show, 1e-9 * one(RG)) == "1.0e-9·(id)"
@test sprint((io, x) -> show(io, "text/latex", x), 1e-9 * one(RG)) == "\$\$ 1.0 \\cdot 10^{-9} \\cdot (id) \$\$"

@test LinearAlgebra.norm(a, 1) == 3

Expand All @@ -92,4 +107,14 @@
@test deepcopy(a) !== a
@test coeffs(deepcopy(a)) !== coeffs(a)
@test parent(deepcopy(a)) === parent(a)

latex = CustomLaTeXPrint(" \$\$ \\[\\(α_β∀ \\) \\]\t \$\$")
@test sprint((io, x) -> show(io, "text/latex", x),
SA.AlgebraElement(SA.SparseCoefficients([p], [latex]), RG)) ==
"\$\$ (α_β∀) \\cdot b·c \$\$"
# Test that the check for `\\)` handles unicode well
latex = CustomLaTeXPrint("\\(β∀")
@test sprint((io, x) -> show(io, "text/latex", x),
SA.AlgebraElement(SA.SparseCoefficients([p], [latex]), RG)) ==
"\$\$ (\\(β∀) \\cdot b·c \$\$"
end

0 comments on commit 7550169

Please sign in to comment.