Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Require Julia 0.7 #127

Merged
merged 8 commits into from Jul 16, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Expand Up @@ -4,7 +4,7 @@ os:
- linux
- osx
julia:
- 0.6
- 0.7
- nightly
matrix:
allow_failures:
Expand Down
5 changes: 2 additions & 3 deletions REQUIRE
@@ -1,5 +1,4 @@
julia 0.6
NLSolversBase 5.0
julia 0.7-beta2
NLSolversBase 7.0
Parameters
NaNMath
Compat
4 changes: 2 additions & 2 deletions appveyor.yml
@@ -1,7 +1,7 @@
environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe"
matrix:
allow_failures:
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
Expand Down
7 changes: 4 additions & 3 deletions docs/generate.jl
Expand Up @@ -3,12 +3,13 @@ import Literate

# TODO: Remove items from `SKIPFILE` as soon as they run on the latest
# stable `Optim` (or other dependency)
#ONLYSTATIC = ["optim_linesearch.jl", "optim_initialstep.jl"]
ONLYSTATIC = []
ONLYSTATIC = ["optim_linesearch.jl", "optim_initialstep.jl"]
#ONLYSTATIC = []

EXAMPLEDIR = joinpath(@__DIR__, "src", "examples")
GENERATEDDIR = joinpath(@__DIR__, "src", "examples", "generated")
for example in filter!(r"\.jl$", readdir(EXAMPLEDIR))
myfilter(str) = occursin(r"\.jl$", str)
for example in filter!(myfilter, readdir(EXAMPLEDIR))
input = abspath(joinpath(EXAMPLEDIR, example))
script = Literate.script(input, GENERATEDDIR)
code = strip(read(script, String))
Expand Down
4 changes: 2 additions & 2 deletions docs/make.jl
Expand Up @@ -11,7 +11,7 @@ makedocs(
format = :html,
sitename = "LineSearches.jl",
doctest = false,
# strict = VERSION.minor == 6 && sizeof(Int) == 8, # only strict mode on 0.6 and Int64
# strict = VERSION.minor == 7 && sizeof(Int) == 8, # only strict mode on 0.7 and Int64
strict = false,
pages = Any[
"Home" => "index.md",
Expand All @@ -27,7 +27,7 @@ makedocs(
deploydocs(
repo = "github.com/JuliaNLSolvers/LineSearches.jl.git",
target = "build",
julia = "0.6", # deploy from release bot
julia = "0.7", # deploy from release bot
deps = nothing,
make = nothing,
)
8 changes: 4 additions & 4 deletions docs/src/examples/customoptimizer.jl
Expand Up @@ -28,11 +28,11 @@ function gdoptimize(f, g!, fg!, x0::AbstractArray{T}, linesearch,
ϕ(α) = f(x .+ α.*s)
function dϕ(α)
g!(gvec, x .+ α.*s)
return vecdot(gvec, s)
return dot(gvec, s)
end
function ϕdϕ(α)
phi = fg!(gvec, x .+ α.*s)
dphi = vecdot(gvec, s)
dphi = dot(gvec, s)
return (phi, dphi)
end

Expand Down Expand Up @@ -100,10 +100,10 @@ ls = BackTracking(order=3)
fx_bt3, x_bt3, iter_bt3 = gdoptimize(f, g!, fg!, x0, ls)

## Test the results #src
using Base.Test #src
using Test #src
@test fx_bt3 < 1e-12 #src
@test iter_bt3 < 10000 #src
@test x_bt3 ≈ [1.0, 1.0] atol=1e-7 #src
@test x_bt3 ≈ [1.0, 1.0] atol=2e-7 #src

# Interestingly, the `StrongWolfe` line search converges in one iteration, whilst
# all the other algorithms take thousands of iterations.
Expand Down
8 changes: 1 addition & 7 deletions docs/src/examples/optim_initialstep.jl
@@ -1,11 +1,5 @@
# # Optim initial step length guess
#
#src TODO: Find a way to run these with Literate when deploying via Travis
#src TODO: This file must currently be run locally and not on CI, and then
#src TODO: the md file must be copied over to the correct directory.
#src TODO: The reason is that there may be breaking changes between Optim and LineSearches,
#src TODO: so we don't want that to mess up JuliaCIBot
#-
#-
#md # !!! tip
#md # This example is also available as a Jupyter notebook:
Expand Down Expand Up @@ -34,7 +28,7 @@ res_hz = Optim.optimize(prob.f, prob.g!, prob.h!, prob.initial_x, method=algo_hz
# From the result we see that this has reduced the number of function and gradient calls, but increased the number of iterations.

## Test the results #src
using Base.Test #src
using Test #src
@test Optim.f_calls(res_hz) < Optim.f_calls(res_st) #src
@test Optim.g_calls(res_hz) < Optim.g_calls(res_st) #src
@test Optim.iterations(res_hz) > Optim.iterations(res_st) #src
9 changes: 2 additions & 7 deletions docs/src/examples/optim_linesearch.jl
@@ -1,10 +1,5 @@
# # Optim line search
#
#src TODO: Find a way to run these with Literate when deploying via Travis
#src TODO: This file must currently be run locally and not on CI, and then
#src TODO: the md file must be copied over to the correct directory.
#src TODO: The reason is that there may be breaking changes between Optim and LineSearches,
#src TODO: so we don't want that to mess up JuliaCIBot
#-
#md # !!! tip
#md # This example is also available as a Jupyter notebook:
Expand Down Expand Up @@ -32,7 +27,7 @@ algo_bt3 = Newton(linesearch = BackTracking(order=3))
res_bt3 = Optim.optimize(prob.f, prob.g!, prob.h!, prob.initial_x, method=algo_bt3)


## Test the results #src
using Base.Test #src
## Test the results #src
using Test #src
@test Optim.f_calls(res_bt3) < Optim.f_calls(res_hz) #src
@test Optim.g_calls(res_bt3) < Optim.g_calls(res_hz) #src
19 changes: 8 additions & 11 deletions src/LineSearches.jl
@@ -1,12 +1,9 @@
isdefined(Base, :__precompile__) && __precompile__()
__precompile__()

module LineSearches

using Compat,
Compat.LinearAlgebra,
Compat.Distributed,
Compat.Printf

using Printf
import LinearAlgebra: dot, norm
using Parameters, NaNMath

import NLSolversBase
Expand Down Expand Up @@ -38,7 +35,7 @@ function make_ϕdϕ(df, x_new, x, s)
NLSolversBase.value_gradient!(df, x_new)

# Calculate ϕ(a_i), ϕ'(a_i)
NLSolversBase.value(df), real(vecdot(NLSolversBase.gradient(df), s))
NLSolversBase.value(df), real(dot(NLSolversBase.gradient(df), s))
end
ϕdϕ
end
Expand All @@ -51,7 +48,7 @@ function make_ϕ_dϕ(df, x_new, x, s)
NLSolversBase.gradient!(df, x_new)

# Calculate ϕ'(a_i)
real(vecdot(NLSolversBase.gradient(df), s))
real(dot(NLSolversBase.gradient(df), s))
end
make_ϕ(df, x_new, x, s), dϕ
end
Expand All @@ -64,7 +61,7 @@ function make_ϕ_dϕ_ϕdϕ(df, x_new, x, s)
NLSolversBase.gradient!(df, x_new)

# Calculate ϕ'(a_i)
real(vecdot(NLSolversBase.gradient(df), s))
real(dot(NLSolversBase.gradient(df), s))
end
function ϕdϕ(α)
# Move a distance of alpha in the direction of s
Expand All @@ -74,7 +71,7 @@ function make_ϕ_dϕ_ϕdϕ(df, x_new, x, s)
NLSolversBase.value_gradient!(df, x_new)

# Calculate ϕ'(a_i)
NLSolversBase.value(df), real(vecdot(NLSolversBase.gradient(df), s))
NLSolversBase.value(df), real(dot(NLSolversBase.gradient(df), s))
end
make_ϕ(df, x_new, x, s), dϕ, ϕdϕ
end
Expand All @@ -87,7 +84,7 @@ function make_ϕ_ϕdϕ(df, x_new, x, s)
NLSolversBase.value_gradient!(df, x_new)

# Calculate ϕ'(a_i)
NLSolversBase.value(df), real(vecdot(NLSolversBase.gradient(df), s))
NLSolversBase.value(df), real(dot(NLSolversBase.gradient(df), s))
end
make_ϕ(df, x_new, x, s), ϕdϕ
end
Expand Down
2 changes: 1 addition & 1 deletion src/backtracking.jl
Expand Up @@ -29,7 +29,7 @@ function (ls::BackTracking)(df::AbstractObjective, x::AbstractArray{T}, s::Abstr
dϕ_0 = dϕ(Tα(0))
end

α_0 = min(α_0, min(alphamax, ls.maxstep / vecnorm(s, Inf)))
α_0 = min(α_0, min(alphamax, ls.maxstep / norm(s, Inf)))
ls(ϕ, α_0, ϕ_0, dϕ_0)
end

Expand Down
34 changes: 19 additions & 15 deletions src/hagerzhang.jl
Expand Up @@ -111,18 +111,19 @@ function (ls::HagerZhang)(ϕ, ϕdϕ,
@unpack delta, sigma, alphamax, rho, epsilon, gamma,
linesearchmax, psi3, display, mayterminate = ls

zeroT = convert(T, 0)

if !(isfinite(phi_0) && isfinite(dphi_0))
throw(ArgumentError("Value and slope at step length = 0 must be finite."))
end
if dphi_0 >= T(0)
if dphi_0 >= zeroT
throw(ArgumentError("Search direction is not a direction of descent."))
end

# Prevent values of x_new = x+αs that are likely to make
# ϕ(x_new) infinite
iterfinitemax::Int = ceil(Int, -log2(eps(T)))
alphas = [T(0)] # for bisection
alphas = [zeroT] # for bisection
values = [phi_0]
slopes = [dphi_0]
if display & LINESEARCH > 0
Expand All @@ -131,7 +132,7 @@ function (ls::HagerZhang)(ϕ, ϕdϕ,


phi_lim = phi_0 + epsilon * abs(phi_0)
@assert c > T(0)
@assert c > zeroT
@assert isfinite(c) && c <= alphamax
phi_c, dphi_c = ϕdϕ(c)
iterfinite = 1
Expand All @@ -142,9 +143,9 @@ function (ls::HagerZhang)(ϕ, ϕdϕ,
phi_c, dphi_c = ϕdϕ(c)
end
if !(isfinite(phi_c) && isfinite(dphi_c))
warn("Failed to achieve finite new evaluation point, using alpha=0")
@warn("Failed to achieve finite new evaluation point, using alpha=0")
mayterminate[] = false # reset in case another initial guess is used next
return T(0.0), ϕ(T(0.0)) # phi_0
return zeroT, ϕ(zeroT) # phi_0
end
push!(alphas, c)
push!(values, phi_c)
Expand Down Expand Up @@ -175,7 +176,7 @@ function (ls::HagerZhang)(ϕ, ϕdϕ,
", phi_c = ", phi_c,
", dphi_c = ", dphi_c)
end
if dphi_c >= T(0)
if dphi_c >= zeroT
# We've reached the upward slope, so we have b; examine
# previous values to find a
ib = length(alphas)
Expand All @@ -191,7 +192,7 @@ function (ls::HagerZhang)(ϕ, ϕdϕ,
# have crested over the peak. Use bisection.
ib = length(alphas)
ia = ib - 1
if c ≉ alphas[ib] || slopes[ib] >= T(0)
if c ≉ alphas[ib] || slopes[ib] >= zeroT
error("c = ", c)
end
# ia, ib = bisect(phi, lsr, ia, ib, phi_lim) # TODO: Pass options
Expand Down Expand Up @@ -226,7 +227,7 @@ function (ls::HagerZhang)(ϕ, ϕdϕ,
if !(isfinite(phi_c) && isfinite(dphi_c))
mayterminate[] = false # reset in case another initial guess is used next
return cold, ϕ(cold)
elseif dphi_c < T(0) && c == alphamax
elseif dphi_c < zeroT && c == alphamax
# We're on the edge of the allowed region, and the
# value is still decreasing. This can be due to
# roundoff error in barrier penalties, a barrier
Expand Down Expand Up @@ -352,7 +353,8 @@ function secant2!(ϕdϕ,
dphi_a = slopes[ia]
dphi_b = slopes[ib]
T = eltype(slopes)
if !(dphi_a < T(0) && dphi_b >= T(0))
zeroT = convert(T, 0)
if !(dphi_a < zeroT && dphi_b >= zeroT)
error(string("Search direction is not a direction of descent; ",
"this error may indicate that user-provided derivatives are inaccurate. ",
@sprintf "(dphi_a = %f; dphi_b = %f)" dphi_a dphi_b))
Expand Down Expand Up @@ -436,10 +438,11 @@ function update!(ϕdϕ,
a = alphas[ia]
b = alphas[ib]
T = eltype(slopes)
zeroT = convert(T, 0)
# Debugging (HZ, eq. 4.4):
@assert slopes[ia] < T(0)
@assert slopes[ia] < zeroT
@assert values[ia] <= phi_lim
@assert slopes[ib] >= T(0)
@assert slopes[ib] >= zeroT
@assert b > a
c = alphas[ic]
phi_c = values[ic]
Expand All @@ -456,7 +459,7 @@ function update!(ϕdϕ,
if c < a || c > b
return ia, ib #, 0, 0 # it's out of the bracketing interval
end
if dphi_c >= T(0)
if dphi_c >= zeroT
return ia, ic #, 0, 0 # replace b with a closer point
end
# We know dphi_c < 0. However, phi may not be monotonic between a
Expand Down Expand Up @@ -485,9 +488,10 @@ function bisect!(ϕdϕ,
a = alphas[ia]
b = alphas[ib]
# Debugging (HZ, conditions shown following U3)
@assert slopes[ia] < T(0)
zeroT = convert(T, 0)
@assert slopes[ia] < zeroT
@assert values[ia] <= phi_lim
@assert slopes[ib] < T(0) # otherwise we wouldn't be here
@assert slopes[ib] < zeroT # otherwise we wouldn't be here
@assert values[ib] > phi_lim
@assert b > a
while b - a > eps(b)
Expand All @@ -503,7 +507,7 @@ function bisect!(ϕdϕ,
push!(slopes, gphi)

id = length(alphas)
if gphi >= T(0)
if gphi >= zeroT
return ia, id # replace b, return
end
if phi_d <= phi_lim
Expand Down