aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Tatham <simon.tatham@arm.com>2018-08-15 12:49:56 +0100
committerSzabolcs Nagy <szabolcs.nagy@arm.com>2018-08-17 16:52:43 +0100
commit757f906d29615b9444ad69429b366eaa7ded3944 (patch)
tree22f5c8963bb4a251d9179ad04d89f14888c18ca0
parent5175759c4908dc4a8c105a4b3990d472803bb91b (diff)
downloadarm-optimized-routines-757f906d29615b9444ad69429b366eaa7ded3944.tar.gz
remez.jl: update to work with Julia 1.0.
This program was originally developed for a much earlier version of Julia, and there have been a lot of changes to Julia semantics since then. But 1.0 is intended to be stable, so updating once to work with that should mean that no further updates are needed for a long time. Changes relevant to this script include new API calls for making arrays, evaluating Julia source-code expressions from strings, and parsing strings as numbers; scope and semantics changes requiring extra escaping in the @debug macro and some explicit 'global' to allow for-loops to update variables outside themselves; a syntax change for tuple types; and replacing 'beginswith' on strings with 'startswith'. There are a couple of remaining inconveniences with this version of the code. Firstly, the standard Julia 1.0 interpreter will consume a "--" option terminator on its command line even if it appears after the script name, so commands of the form 'julia remez.jl -- -1 1 ...' that worked in Julia 0.2 will no longer work. Adding an extra "--" before the script name works around this ('julia -- remez.jl -- ...') because the first "--" is seen by the Julia interpreter and the second goes to the script. But unfortunately that "--" can't be put in the #! line as well as the 'env', because of #! command line semantics. So users may have to work around this by explicitly invoking the interpreter. Secondly, Julia 1.0 has moved some mathematical functions (e.g. erf and gamma) out of its core library into the SpecialFunctions package, so any pre-existing command lines that used those functions will now need to qualify them with a package name, and be run on a Julia installation which has that package installed. Because Julia 0.4.x is still common (Ubuntu 16.04 and 18.04 both provide 0.4.5), I've included some backwards-compatibility code so that the script still runs on that version as well.
-rwxr-xr-xauxiliary/remez.jl117
1 files changed, 72 insertions, 45 deletions
diff --git a/auxiliary/remez.jl b/auxiliary/remez.jl
index 31266e9..01e62f9 100755
--- a/auxiliary/remez.jl
+++ b/auxiliary/remez.jl
@@ -18,6 +18,30 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import Base.\
+
+# ----------------------------------------------------------------------
+# Helper functions to cope with different Julia versions.
+if VERSION >= v"0.7.0"
+ array1d(T, d) = Array{T, 1}(undef, d)
+ array2d(T, d1, d2) = Array{T, 2}(undef, d1, d2)
+else
+ array1d(T, d) = Array(T, d)
+ array2d(T, d1, d2) = Array(T, d1, d2)
+end
+if VERSION < v"0.5.0"
+ String = ASCIIString
+end
+if VERSION >= v"0.6.0"
+ # Use Base.invokelatest to run functions made using eval(), to
+ # avoid "world age" error
+ run(f, x...) = Base.invokelatest(f, x...)
+else
+ # Prior to 0.6.0, invokelatest doesn't exist (but fortunately the
+ # world age problem also doesn't seem to exist)
+ run(f, x...) = f(x...)
+end
+
# ----------------------------------------------------------------------
# Global variables configured by command-line options.
floatsuffix = "" # adjusted by --floatsuffix
@@ -26,7 +50,7 @@ epsbits = 256 # adjusted by --bits
debug_facilities = Set() # adjusted by --debug
full_output = false # adjusted by --full
array_format = false # adjusted by --array
-preliminary_commands = String[] # adjusted by --pre
+preliminary_commands = array1d(String, 0) # adjusted by --pre
# ----------------------------------------------------------------------
# Diagnostic and utility functions.
@@ -56,7 +80,7 @@ macro debug(facility, printargs...)
for arg in printargs
printit = quote
$printit
- print($arg)
+ print($(esc(arg)))
end
end
return quote
@@ -156,7 +180,7 @@ end
# xys Array of (x,y) pairs of BigFloats.
#
# Return value is a string.
-function format_xylist(xys::Array{(BigFloat,BigFloat)})
+function format_xylist(xys::Array{Tuple{BigFloat,BigFloat}})
return ("[\n" *
join([" "*string(x)*" -> "*string(y) for (x,y) in xys], "\n") *
"\n]")
@@ -354,8 +378,8 @@ function ratfn_leastsquares(f::Function, xvals::Array{BigFloat}, n, d,
# Build the matrix. We're solving n+d+1 equations in n+d+1
# unknowns. (We actually have to return n+d+2 coefficients, but
# one of them is hardwired to 1.)
- matrix = Array(BigFloat, n+d+1, n+d+1)
- vector = Array(BigFloat, n+d+1)
+ matrix = array2d(BigFloat, n+d+1, n+d+1)
+ vector = array1d(BigFloat, n+d+1)
for i = 0:1:n
# Equation obtained by differentiating with respect to p_i,
# i.e. the numerator coefficient of x^i.
@@ -484,7 +508,7 @@ end
# the extremum location and its value (i.e. y=f(x)).
function find_extrema(f::Function, grid::Array{BigFloat})
len = length(grid)
- extrema = Array((BigFloat, BigFloat), 0)
+ extrema = array1d(Tuple{BigFloat, BigFloat}, 0)
for i = 1:1:len
# We have to provide goldensection() with three points
# bracketing the extremum. If the extremum is at one end of
@@ -529,11 +553,11 @@ end
# Returns a new array of (x,y) pairs which is a subsequence of the
# original sequence. (So, in particular, if the input was sorted by x
# then so will the output be.)
-function winnow_extrema(extrema::Array{(BigFloat,BigFloat)}, n)
+function winnow_extrema(extrema::Array{Tuple{BigFloat,BigFloat}}, n)
# best[i,j] gives the best sequence so far of length i and with
# sign j (where signs are coded as 1=positive, 2=negative), in the
# form of a tuple (cost, actual array of x,y pairs).
- best = fill((BigFloat(0), Array((BigFloat,BigFloat),0)), n, 2)
+ best = fill((BigFloat(0), array1d(Tuple{BigFloat,BigFloat}, 0)), n, 2)
for (x,y) = extrema
if y > 0
@@ -624,8 +648,8 @@ function ratfn_equal_deviation(f::Function, coords::Array{BigFloat},
# in which the p_i and e are the variables, and the powers of
# x and calls to w and f are the coefficients.
- matrix = Array(BigFloat, n+2, n+2)
- vector = Array(BigFloat, n+2)
+ matrix = array2d(BigFloat, n+2, n+2)
+ vector = array1d(BigFloat, n+2)
currsign = +1
for i = 1:1:n+2
x = coords[i]
@@ -678,8 +702,8 @@ function ratfn_equal_deviation(f::Function, coords::Array{BigFloat},
# based on the first n+d+1 of the n+d+2 coordinates, and
# see what the error turns out to be at the final
# coordinate.
- matrix = Array(BigFloat, n+d+1, n+d+1)
- vector = Array(BigFloat, n+d+1)
+ matrix = array2d(BigFloat, n+d+1, n+d+1)
+ vector = array1d(BigFloat, n+d+1)
currsign = +1
for i = 1:1:n+d+1
x = coords[i]
@@ -787,7 +811,7 @@ end
# means that the Chebyshev alternation theorem guarantees
# that any other function of the same degree must exceed
# the error of this one at at least one of those points.
-function ratfn_minimax(f::Function, interval::(BigFloat,BigFloat), n, d,
+function ratfn_minimax(f::Function, interval::Tuple{BigFloat,BigFloat}, n, d,
w = (x,y)->BigFloat(1))
# We start off by finding a least-squares approximation. This
# doesn't need to be perfect, but if we can get it reasonably good
@@ -934,7 +958,7 @@ function test()
# Test leastsquares rational functions.
println("Leastsquares test 1:")
n = 10000
- a = Array(BigFloat, n+1)
+ a = array1d(BigFloat, n+1)
for i = 0:1:n
a[1+i] = i/BigFloat(n)
end
@@ -947,7 +971,7 @@ function test()
# Test golden section search.
println("Golden section test 1:")
x, y = goldensection(x->sin(x),
- BigFloat(0), BigFloat("0.1"), BigFloat(4))
+ BigFloat(0), BigFloat(1)/10, BigFloat(4))
println(" ", x, " -> ", y)
test(approx_eq(x, asin(BigFloat(1))))
test(approx_eq(y, 1))
@@ -955,7 +979,7 @@ function test()
# Test extrema-winnowing algorithm.
println("Winnow test 1:")
extrema = [(x, sin(20*x)*sin(197*x))
- for x in BigFloat(0):BigFloat("0.001"):BigFloat(1)]
+ for x in BigFloat(0):BigFloat(1)/1000:BigFloat(1)]
winnowed = winnow_extrema(extrema, 12)
println(" ret = ", format_xylist(winnowed))
prevx, prevy = -1, 0
@@ -973,7 +997,7 @@ function test()
println(" ",e)
println(" ",ratfn_to_string(nc, dc))
test(0 < e < 1e-3)
- for x = 0:BigFloat(0.001):1
+ for x = 0:BigFloat(1)/1000:1
test(abs(ratfn_eval(nc, dc, x) - exp(x)) <= e * 1.0000001)
end
@@ -982,7 +1006,7 @@ function test()
println(" ",e)
println(" ",ratfn_to_string(nc, dc))
test(0 < e < 1e-3)
- for x = 0:BigFloat(0.001):1
+ for x = 0:BigFloat(1)/1000:1
test(abs(ratfn_eval(nc, dc, x) - exp(x)) <= e * 1.0000001)
end
@@ -992,7 +1016,7 @@ function test()
println(" ",e)
println(" ",ratfn_to_string(nc, dc))
test(0 < e < 1e-3)
- for x = 0:BigFloat(0.001):1
+ for x = 0:BigFloat(1)/1000:1
test(abs(ratfn_eval(nc, dc, x) - exp(x))/exp(x) <= e * 1.0000001)
end
@@ -1002,7 +1026,7 @@ function test()
println(" ",e)
println(" ",ratfn_to_string(nc, dc))
test(0 < e < 1e-3)
- for x = 0:BigFloat(0.001):1
+ for x = 0:BigFloat(1)/1000:1
test(abs(ratfn_eval(nc, dc, x) - exp(x))/exp(x) <= e * 1.0000001)
end
@@ -1012,12 +1036,12 @@ function test()
println(" ",e)
println(" ",ratfn_to_string(nc, dc))
test(0 < e < 1e-3)
- for x = 0:BigFloat(0.001):1
+ for x = 0:BigFloat(1)/1000:1
test(abs(ratfn_eval(nc, dc, x) - exp(x))/exp(x) <= e * 1.0000001)
end
total = passes + fails
- @printf "%d passes %d fails %d total\n" passes fails total
+ println(passes, " passes ", fails, " fails ", total, " total")
end
# ----------------------------------------------------------------------
@@ -1206,14 +1230,14 @@ function main()
end
for preliminary_command in preliminary_commands
- eval(parse(preliminary_command))
+ eval(Meta.parse(preliminary_command))
end
- lo = BigFloat(eval(parse(argwords[1])))
- hi = BigFloat(eval(parse(argwords[2])))
- n = int(argwords[3])
- d = int(argwords[4])
- f = eval(parse("x -> " * argwords[5]))
+ lo = BigFloat(eval(Meta.parse(argwords[1])))
+ hi = BigFloat(eval(Meta.parse(argwords[2])))
+ n = parse(Int,argwords[3])
+ d = parse(Int,argwords[4])
+ f = eval(Meta.parse("x -> " * argwords[5]))
# Wrap the user-provided function with a function of our own. This
# arranges to detect silly FP values (inf,nan) early and diagnose
@@ -1221,7 +1245,7 @@ function main()
# function in case you suspect it's doing the wrong thing at some
# special-case point.
function func(x)
- y = f(x)
+ y = run(f,x)
@debug("f", x, " -> ", y)
if !isfinite(y)
error("f(" * string(x) * ") returned non-finite value " * string(y))
@@ -1231,9 +1255,9 @@ function main()
if nargs == 6
# Wrap the user-provided weight function similarly.
- w = eval(parse("(x,y) -> " * argwords[6]))
+ w = eval(Meta.parse("(x,y) -> " * argwords[6]))
function wrapped_weight(x,y)
- ww = w(x,y)
+ ww = run(w,x,y)
if !isfinite(ww)
error("w(" * string(x) * "," * string(y) *
") returned non-finite value " * string(ww))
@@ -1283,9 +1307,11 @@ end
what_to_do = main
doing_opts = true
-argwords = Array(ASCIIString, 0)
+argwords = array1d(String, 0)
for arg = ARGS
- if doing_opts && beginswith(arg, "-")
+ global doing_opts, what_to_do, argwords
+ global full_output, array_format, xvarname, floatsuffix, epsbits
+ if doing_opts && startswith(arg, "-")
if arg == "--"
doing_opts = false
elseif arg == "--help"
@@ -1296,18 +1322,19 @@ for arg = ARGS
full_output = true
elseif arg == "--array"
array_format = true
- elseif beginswith(arg, "--debug=")
- enable_debug(arg[length("--debug=")+1:])
- elseif beginswith(arg, "--variable=")
- xvarname = arg[length("--variable=")+1:]
- elseif beginswith(arg, "--suffix=")
- floatsuffix = arg[length("--suffix=")+1:]
- elseif beginswith(arg, "--bits=")
- epsbits = int(arg[length("--bits=")+1:])
- elseif beginswith(arg, "--bigfloatbits=")
- set_bigfloat_precision(int(arg[length("--bigfloatbits=")+1:]))
- elseif beginswith(arg, "--pre=")
- push!(preliminary_commands, arg[length("--pre=")+1:])
+ elseif startswith(arg, "--debug=")
+ enable_debug(arg[length("--debug=")+1:end])
+ elseif startswith(arg, "--variable=")
+ xvarname = arg[length("--variable=")+1:end]
+ elseif startswith(arg, "--suffix=")
+ floatsuffix = arg[length("--suffix=")+1:end]
+ elseif startswith(arg, "--bits=")
+ epsbits = parse(Int,arg[length("--bits=")+1:end])
+ elseif startswith(arg, "--bigfloatbits=")
+ set_bigfloat_precision(
+ parse(Int,arg[length("--bigfloatbits=")+1:end]))
+ elseif startswith(arg, "--pre=")
+ push!(preliminary_commands, arg[length("--pre=")+1:end])
else
error("unrecognised option: ", arg)
end