Skip to content

Commit 6de5353

Browse files
Add implementation
1 parent 830f7fc commit 6de5353

File tree

5 files changed

+144
-18
lines changed

5 files changed

+144
-18
lines changed

Project.toml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
11
name = "AbsentTypes"
2-
uuid = "806a83c1-d09f-449d-ab1d-4e49ad4cc0e9"
2+
uuid = "0d71be07-595a-4f89-9529-4065a4ab43a6"
33
authors = ["CliMA Contributors <[email protected]>"]
44
version = "0.1.0"
55

6+
[compat]
7+
Aqua = "0.8"
8+
Test = "1"
9+
LazyBroadcast = "1"
10+
julia = "1.8"
11+
612
[extras]
713
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
14+
Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595"
15+
LazyBroadcast = "9dccce8e-a116-406d-9fcc-a88ed4f510c8"
816

917
[targets]
10-
test = ["Test"]
18+
test = ["Test", "Aqua", "LazyBroadcast"]

docs/Project.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
[deps]
22
Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4"
33
DocumenterCitations = "daee34ce-89f3-4625-b898-19384cb65244"
4-
AbsentTypes = "806a83c1-d09f-449d-ab1d-4e49ad4cc0e9"
4+
AbsentTypes = "0d71be07-595a-4f89-9529-4065a4ab43a6"

docs/make.jl

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,7 @@ import AbsentTypes
44
bib = DocumenterCitations.CitationBibliography(joinpath(@__DIR__, "refs.bib"))
55

66
mathengine = Documenter.MathJax(
7-
Dict(
8-
:TeX => Dict(
9-
:equationNumbers => Dict(:autoNumber => "AMS"),
10-
:Macros => Dict(),
11-
),
12-
),
7+
Dict(:TeX => Dict(:equationNumbers => Dict(:autoNumber => "AMS"), :Macros => Dict())),
138
)
149

1510
format = Documenter.HTML(
@@ -26,11 +21,7 @@ Documenter.makedocs(;
2621
clean = true,
2722
doctest = true,
2823
modules = [AbsentTypes],
29-
pages = Any[
30-
"Home" => "index.md",
31-
"API" => "api.md",
32-
"References" => "references.md",
33-
],
24+
pages = Any["Home"=>"index.md", "API"=>"api.md", "References"=>"references.md"],
3425
)
3526

3627
Documenter.deploydocs(

src/AbsentTypes.jl

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,76 @@
11
module AbsentTypes
22

3-
greet() = print("Hello World!")
3+
"""
4+
Absent()
5+
6+
A `Base.AbstractBroadcasted` that represents arithmetic object.
7+
8+
An `Absent()` can be added to, subtracted from, or multiplied by any value in a
9+
broadcast expression without incurring a runtime performance penalty.
10+
11+
For example, the following rules hold when broadcasting instances of `Absent`:
12+
```
13+
1 + Absent() == 1
14+
Absent() + 1 == 1
15+
1 - Absent() == 1
16+
1 * Absent() == Absent()
17+
1 / Absent() == Absent()
18+
```
19+
"""
20+
struct Absent <: Base.AbstractBroadcasted end
21+
Base.broadcastable(x::Absent) = x
22+
23+
struct AbsentStyle <: Base.BroadcastStyle end
24+
Base.BroadcastStyle(::Type{<:Absent}) = Absent()
25+
26+
# Specialize on AbstractArrayStyle to avoid ambiguities with AbstractBroadcasted.
27+
Base.BroadcastStyle(::Absent, ::Base.Broadcast.AbstractArrayStyle) = Absent()
28+
Base.BroadcastStyle(::Base.Broadcast.AbstractArrayStyle, ::Absent) = Absent()
29+
30+
# Add another method to avoid ambiguity between the previous two.
31+
Base.BroadcastStyle(::Absent, ::Absent) = Absent()
32+
33+
broadcasted_sum(args) =
34+
if isempty(args)
35+
Absent()
36+
elseif length(args) == 1
37+
args[1]
38+
else
39+
Base.broadcasted(+, args...)
40+
end
41+
Base.broadcasted(::Absent, ::typeof(+), args...) =
42+
broadcasted_sum(filter(arg -> !(arg isa Absent), args))
43+
44+
Base.broadcasted(op::typeof(-), ::Absent, arg) = Base.broadcasted(op, arg)
45+
Base.broadcasted(op::typeof(-), arg, ::Absent) = Base.broadcasted(Base.identity, arg)
46+
Base.broadcasted(op::typeof(-), a::Absent) = Absent()
47+
Base.broadcasted(op::typeof(-), a::Absent, ::Absent) = Base.broadcasted(op, a)
48+
49+
Base.broadcasted(op::typeof(+), ::Absent, args...) = Base.broadcasted(op, args...)
50+
Base.broadcasted(op::typeof(+), arg, ::Absent) = Base.broadcasted(op, arg)
51+
Base.broadcasted(op::typeof(+), a::Absent, ::Absent) = Base.broadcasted(op, a)
52+
53+
Base.broadcasted(op::typeof(*), ::Absent, args...) = Absent()
54+
Base.broadcasted(op::typeof(*), arg, ::Absent) = Absent()
55+
Base.broadcasted(op::typeof(*), ::Absent, ::Absent) = Absent()
56+
Base.broadcasted(op::typeof(/), ::Absent, args...) = Absent()
57+
Base.broadcasted(op::typeof(/), arg, ::Absent) = Absent()
58+
Base.broadcasted(op::typeof(/), ::Absent, ::Absent) = Absent()
59+
60+
function skip_materialize(dest, bc::Base.Broadcast.Broadcasted)
61+
if typeof(bc.f) <: typeof(+) || typeof(bc.f) <: typeof(-)
62+
if length(bc.args) == 2 &&
63+
bc.args[1] === dest &&
64+
bc.args[2] === Base.Broadcast.Broadcasted(Absent, ())
65+
return true
66+
else
67+
return false
68+
end
69+
else
70+
return false
71+
end
72+
end
73+
74+
Base.Broadcast.instantiate(bc::Base.Broadcast.Broadcasted{AbsentStyle}) = x
475

576
end # module AbsentTypes

test/runtests.jl

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,67 @@
1+
#=
2+
julia --project
3+
using Revise; using TestEnv; TestEnv.activat(); include("test/runtests.jl")
4+
=#
15
using Test
26
using AbsentTypes
7+
using AbsentTypes: Absent
38
using Aqua
9+
using LazyBroadcast: lazy
10+
import Base.Broadcast: instantiate, materialize, Broadcasted, DefaultArrayStyle
411

5-
@testset "AbsentTypes" begin
6-
@test 1 == 1
12+
@testset "Absent" begin
13+
x = [1]
14+
a = Absent()
15+
@test typeof(lazy.(x .+ a)) <: Broadcasted{
16+
DefaultArrayStyle{1},
17+
Tuple{Base.OneTo{Int64}},
18+
typeof(+),
19+
Tuple{Vector{Int64}},
20+
}
21+
@test typeof(lazy.(a .+ x)) <: Broadcasted{
22+
DefaultArrayStyle{1},
23+
Tuple{Base.OneTo{Int64}},
24+
typeof(+),
25+
Tuple{Vector{Int64}},
26+
}
27+
@test lazy.(a .* x) isa Absent
28+
@test lazy.(a ./ x) isa Absent
29+
30+
# +
31+
@test materialize(lazy.(a .+ x .+ 1)) == [2]
32+
@test materialize(lazy.(a .+ 1 .+ x)) == [2]
33+
@test materialize(lazy.(1 .+ a .+ x)) == [2]
34+
@test materialize(lazy.(1 .+ x .+ a)) == [2]
35+
36+
# -
37+
@test materialize(lazy.(a .- x .- 1)) == [-2]
38+
@test materialize(lazy.(a .- 1 .- x)) == [-2]
39+
@test materialize(lazy.(1 .- a .- x)) == [0]
40+
@test materialize(lazy.(1 .- x .- a)) == [0]
41+
@test materialize(lazy.(a .- a)) == Absent()
42+
@test materialize(lazy.(1 .- 1 .+ a .- a)) == 0
43+
@test materialize(lazy.(x .- x .+ a .- a)) == [0]
44+
45+
# *
46+
@test materialize(lazy.(a .* x .* 1)) == Absent()
47+
@test materialize(lazy.(a .* 1 .* x)) == Absent()
48+
@test materialize(lazy.(1 .* a .* x)) == Absent()
49+
@test materialize(lazy.(1 .* x .* a)) == Absent()
50+
51+
# /
52+
@test materialize(lazy.(a ./ x ./ 1)) == Absent()
53+
@test materialize(lazy.(a ./ 1 ./ x)) == Absent()
54+
@test materialize(lazy.(1 ./ a ./ x)) == Absent()
55+
@test materialize(lazy.(1 ./ x ./ a)) == Absent()
56+
57+
@test_throws MethodError Absent() + 1
58+
@test_throws MethodError Absent() - 1
59+
@test_throws MethodError Absent() * 1
60+
@test_throws MethodError Absent() / 1
61+
62+
@test materialize(Absent()) isa Absent
763
end
864

965
@testset "Aqua" begin
10-
@test Aqua.test_all(AbsentTypes)
66+
Aqua.test_all(AbsentTypes)
1167
end

0 commit comments

Comments
 (0)