#!/usr/bin/env ruby # Ruby/GSL implementation of GSL "min/test.c" require("gsl") require("./gsl_test2.rb") include GSL::Test include Math GSL::IEEE::env_setup() EPSABS = 0.001 EPSREL = 0.001 MAX_ITERATIONS = 100 def within_tol(a, b, epsrel, epsabs) (a - b).abs < (epsrel*GSL::MIN(a.abs, b.abs) + epsabs) end def test_f(type, desc, f, lower, mid, upper, min) x_lower = lower x_upper = upper s = GSL::Min::FMinimizer.alloc(type) s.set(f, mid, x_lower, x_upper) iterations = 0 begin iterations += 1 status = s.iterate m = s.x_minimum a = s.x_lower b = s.x_upper if a > b desc2 = sprintf("interval is invalid (%g,%g)", a, b) GSL::Test::test(GSL::FAILURE, desc2) end if m < a or m > b desc2 = sprintf("m lies outside interval %g (%g,%g)", m, a, b) GSL::Test::test(GSL::FAILURE, desc2) end if status == 1; break; end status = GSL::Min.test_interval(a, b, EPSABS, EPSREL) end while status == GSL::CONTINUE and iterations < MAX_ITERATIONS desc2 = sprintf("%s, %s (%g obs vs %g expected) ", s.name, desc, s.x_minimum, min) GSL::Test::test(status, desc2) if !within_tol(m, min, EPSREL, EPSABS) desc2 = sprintf("incorrect precision (%g obs vs %g expected)", m, min) GSL::Test::test(GSL::FAILURE, desc2) end end def test_f_e(type, desc, f, lower, mid, upper, min) x_lower = lower x_upper = upper s = GSL::Min::FMinimizer.alloc(type) status = nil begin status = s.set(f, mid, x_lower, x_upper) rescue end if status != GSL::SUCCESS desc2 = sprintf("%s, %s", s.name, desc) GSL::Test::test(status == GSL::SUCCESS ? 1 : 0, desc2) end iterations = 0 begin iterations += 1 status = s.iterate m = s.x_minimum a = s.x_lower b = s.x_upper status = GSL::Min.test_interval(a, b, EPSABS, EPSREL) rescue end while status == GSL::CONTINUE and iterations < MAX_ITERATIONS # desc2 = sprintf("%s, %s", s.name, desc) # GSL::Test::test(status == 0 ? 0 : 1, desc2) end F_cos = GSL::Function.alloc { |x| cos(x) } Func1 = GSL::Function.alloc { |x| pow(x, 4.0) - 1 } Func2 = GSL::Function.alloc { |x| sqrt(x.abs) } Func3 = GSL::Function.alloc { |x| if x < 1.0 1 else -exp(-x) end } Func4 = GSL::Function.alloc { |x| x - 30.0/(1.0 + 1e5*pow(x - 0.8, 2.0)) } types = ["goldensection", "brent", "quad_golden"] types.each do |t| test_f(t, "cos(x) [0 (3) 6]", F_cos, 0.0, 3.0, 6.0, M_PI) test_f(t, "x^4 - 1 [-3 (-1) 17]", Func1, -3.0, -1.0, 17.0, 0.0); test_f(t, "sqrt(|x|) [-2 (-1) 1.5]", Func2, -2.0, -1.0, 1.5, 0.0); test_f(t, "func3(x) [-2 (3) 4]", Func3, -2.0, 3.0, 4.0, 1.0); test_f(t, "func4(x) [0 (0.782) 1]", Func4, 0, 0.782, 1.0, 0.8); test_f_e(t, "invalid range check [4, 0]", F_cos, 4.0, 3.0, 0.0, M_PI); test_f_e(t, "invalid range check [1, 1]", F_cos, 1.0, 1.0, 1.0, M_PI); test_f_e(t, "invalid range check [-1, 1]", F_cos, -1.0, 0.0, 1.0, M_PI) end