Skip to content

Commit 9e8d36c

Browse files
moritzdrechselgraustevengj
authored andcommitted
Fix constructor of ScaledSobolSeq (#17)
* fix bug in constructors for ScaledSobolSeq add next!(s::ScaledSobolSeq) to allow for iteration over ScaledSobolSeq * use type params in inner constructor, more tests, users don't call ScaledSobolSeq directly, support AbstractVector * copyto! for Julia 0.7 and 1.0 * don't make extra copies if data is Vector{Float64} already * support SobolSeq(lb, ub) for iterators * safer to always make a copy
1 parent bc88e65 commit 9e8d36c

File tree

3 files changed

+43
-22
lines changed

3 files changed

+43
-22
lines changed

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ facts it is not copyrightable.) SGJ's implementation in NLopt, along
4545
with this Julia translation, is free/open-source software under the [MIT
4646
("expat") license](http://opensource.org/licenses/MIT).
4747

48-
Direction numbers used were derived from the file
48+
Direction numbers used were derived from the file
4949
http://web.maths.unsw.edu.au/~fkuo/sobol/new-joe-kuo-6.21201
5050

5151
Technically, we implement a 32-bit Sobol sequence. After
@@ -84,13 +84,13 @@ Note, however, that the loop will *never terminate* unless you explicitly
8484
call `break` (or similar) in the loop body at some point of your choosing.
8585

8686
We also provide a different `SobolSeq` constructor to provide
87-
a Sobol sequence rescaled to an arbitrary hypercube:
87+
an `N`-dimensional Sobol sequence rescaled to an arbitrary hypercube:
8888
```
89-
s = SobolSeq(N, lb, ub)
89+
s = SobolSeq(lb, ub)
9090
```
9191
where `lb` and `ub` are arrays (or other iterables) of length `N`, giving
9292
the lower and upper bounds of the hypercube, respectively. For example,
93-
`SobolSeq(2, [-1,0,0],[1,3,2])` generates points in the box [-1,1]×[0,3]×[0,2].
93+
`SobolSeq([-1,0,0],[1,3,2])` generates points in the box [-1,1]×[0,3]×[0,2].
9494

9595
If you know in advance the number `n` of points that you plan to
9696
generate, some authors suggest that better uniformity can be attained

src/Sobol.jl

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,14 @@ struct ScaledSobolSeq{N} <: AbstractSobolSeq{N}
122122
s::SobolSeq{N}
123123
lb::Vector{Float64}
124124
ub::Vector{Float64}
125-
ScaledSobolSeq(lb::Vector{Float64}, ub::Vector{Float64}) =
126-
new{N}(SobolSeq(N), lb, ub)
125+
function ScaledSobolSeq{N}(lb::Vector{Float64}, ub::Vector{Float64}) where {N}
126+
length(lb)==length(ub)==N || throw(DimensionMismatch("lb and ub do not have length $N"))
127+
new(SobolSeq(N), lb, ub)
128+
end
127129
end
128130
SobolSeq(N::Integer, lb, ub) =
129-
ScaledSobolSeq{Int(N)}(copy!(Vector{Float64}(undef,N), lb), copy!(Vector{Float64}(undef,N), ub))
131+
ScaledSobolSeq{Int(N)}(copyto!(Vector{Float64}(undef,N), lb), copyto!(Vector{Float64}(undef,N), ub))
132+
SobolSeq(lb, ub) = SobolSeq(length(lb), lb, ub)
130133

131134
function next!(s::SobolSeq, x::AbstractVector{<:AbstractFloat},
132135
lb::AbstractVector, ub::AbstractVector)
@@ -140,6 +143,7 @@ end
140143
next!(s::SobolSeq{N}, lb::AbstractVector, ub::AbstractVector) where {N} = next!(s, Vector{Float64}(undef, N), lb, ub)
141144

142145
next!(s::ScaledSobolSeq, x::AbstractVector{<:AbstractFloat}) = next!(s.s, x, s.lb, s.ub)
146+
next!(s::ScaledSobolSeq) = next!(s.s, Array{Float64,1}(undef, ndims(s)), s.lb, s.ub)
143147
next(s::ScaledSobolSeq) = next!(s, Vector{Float64}(undef, ndims(s)))
144148

145149
Base.skip(s::ScaledSobolSeq, n) = skip(s.s, n)

test/runtests.jl

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,50 @@
11
using Sobol, Compat
22
using Compat.Test
33

4-
# compare results with results from C++ code sobol.cc published on
4+
# compare results with results from C++ code sobol.cc published on
55
# http://web.maths.unsw.edu.au/~fkuo/sobol/
66
# with new-joe-kuo-6.21201 file used as input.
77
#
8-
# Command line used to generate output is
8+
# Command line used to generate output is
99
# ./sobol $N 1024 new-joe-kuo-6.21201 > exp_results_$N
1010
#
1111
# For each of the dimensions below
1212
# (except 21201 where only 64 samples are generated)
1313

14-
dimensions = [5, 10, 20, 50, 100, 500, 21201]
14+
@testset "published results" begin
15+
dimensions = [5, 10, 20, 50, 100, 500, 21201]
1516

16-
for dim in dimensions
17-
println("Testing dimension $(dim)")
18-
open(joinpath(dirname(@__FILE__), "results", "exp_results_$(dim)")) do exp_results_file
19-
s = SobolSeq(dim)
20-
x = zeros(dim)
21-
for line in eachline(exp_results_file)
22-
values = [parse(Float64, item) for item in split(line)]
23-
if length(values) > 0
24-
@test x == values
25-
next!(s, x)
17+
for dim in dimensions
18+
println("Testing dimension $(dim)")
19+
open(joinpath(dirname(@__FILE__), "results", "exp_results_$(dim)")) do exp_results_file
20+
s = SobolSeq(dim)
21+
x = zeros(dim)
22+
for line in eachline(exp_results_file)
23+
values = [parse(Float64, item) for item in split(line)]
24+
if length(values) > 0
25+
@test x == values
26+
next!(s, x)
27+
end
2628
end
2729
end
2830
end
2931
end
3032

31-
# issue #8
3233
using Base.Iterators: take
33-
@test [x[1] for x in collect(take(Sobol.SobolSeq(1),5))] == [0.5,0.75,0.25,0.375,0.875]
34+
@testset "iterators" begin
35+
# issue #8
36+
@test [x[1] for x in collect(take(Sobol.SobolSeq(1),5))] == [0.5,0.75,0.25,0.375,0.875]
37+
end
38+
39+
@testset "scaled" begin
40+
# ScaledSobolSeq constructors
41+
lb = [-1,0,0]
42+
ub = [1,3,2]
43+
N = length(lb)
44+
s = SobolSeq(lb,ub)
45+
@test s isa ScaledSobolSeq{3}
46+
@test first(s) == [0,1.5,1]
47+
@test first(SobolSeq((x for x in lb), (x for x in ub))) == [0,1.5,1]
48+
@test SobolSeq(N,lb,ub) isa ScaledSobolSeq{3}
49+
@test_throws BoundsError SobolSeq(2,lb,ub)
50+
end

0 commit comments

Comments
 (0)