func Brent(fn Diffable, x_lo, x_hi, epsAbs, epsRel float64) (float64, error) { cfn := unsafe.Pointer(&fn) result := C.double(0.0) err := C.brentSolve(cfn, C.double(x_lo), C.double(x_hi), C.double(epsAbs), C.double(epsRel), &result) if err != C.GSL_SUCCESS { err_str := C.GoString(C.gsl_strerror(err)) return 0.0, fmt.Errorf("error in solve.Brent: %v\n", err_str) } return float64(result), nil }
// Perform a fit for p = len(`start`) parameters on `n` functions `F` (with // derivatives `Df`). F(x, i) and Df(x, i) must be defined for 0 <= i < n. If // x (a vector of dimension p) is outside the domain of F or Df, they should // return an error. func MultiDim(F FitErrF, Df FitErrDf, n int, start vec.Vector, epsAbs, epsRel float64) (vec.Vector, error) { fns := FitData{F, Df, n} cfns := unsafe.Pointer(&fns) p := C.size_t(len(start)) csolution, cstart := C.gsl_vector_alloc(p), C.gsl_vector_alloc(p) vecToGSL(start, cstart) err := C.multiFit(cfns, cstart, C.double(epsAbs), C.double(epsRel), C.size_t(n), csolution) if err != C.GSL_SUCCESS { err_str := C.GoString(C.gsl_strerror(err)) return nil, fmt.Errorf("error in fit.MultiDim: %v\n", err_str) } solution := vecFromGSL(csolution) C.gsl_vector_free(csolution) C.gsl_vector_free(cstart) return solution, nil }
// Numerical central derivative of fn(v) with respect to v_i within tolerance // epsabs. h is the initial step size. func Derivative(fn vec.FnDim0, v vec.Vector, i int, h, epsabs float64) (float64, error) { v_i_initial := v[i] iters, maxIters := 0, 100 // results are bad for h too small or too large; we iterate in both directions hMin := h / 1e6 hMax := h * 1e6 hRising := true hInitial := h hOk := func(h float64) bool { if !hRising && h > hMin { return true } else if hRising && h < hMax { return true } return false } hAdvance := func(h float64) float64 { if hRising { if h*2.0 > hMax { hRising = false return hInitial / 2.0 } return h * 2.0 } return h / 2.0 } fwi := unsafe.Pointer(&fnWithIndex{fn, v, i}) x := C.double(v[i]) result, abserr := C.double(0.0), C.double(math.MaxFloat64) for iters < maxIters && hOk(h) { err := C.centralDeriv(fwi, x, C.double(h), &result, &abserr) if err != C.GSL_SUCCESS { err_str := C.GoString(C.gsl_strerror(err)) v[i] = v_i_initial return float64(result), fmt.Errorf("error in Derivative (GSL): %v\n", err_str) } if float64(abserr) < epsabs { v[i] = v_i_initial return float64(result), nil } iters++ h = hAdvance(h) } // if we get here, !hOk(h) || iters == maxIters v[i] = v_i_initial return float64(result), fmt.Errorf("Derivative exceeded maximum iterations\n") }
// Multidimensional root-finder. Implemented by providing an interface to GSL // implementation of Powell's Hybrid method (gsl_multiroot_fdfsolver_hybridsj). // Callback passing through cgo follows the model at: // http://stackoverflow.com/questions/6125683/call-go-functions-from-c/6147097#6147097 func MultiDim(fn DiffSystem, start vec.Vector, epsAbs, epsRel float64) (vec.Vector, error) { cfn := unsafe.Pointer(&fn) dim := C.size_t(fn.Dimension) csolution, cstart := C.gsl_vector_alloc(dim), C.gsl_vector_alloc(dim) VecToGSL(start, cstart) err := C.powellSolve(cfn, cstart, C.double(epsAbs), C.double(epsRel), csolution) if err != C.GSL_SUCCESS { err_str := C.GoString(C.gsl_strerror(err)) return nil, fmt.Errorf("error in solve.MultiDim: %v\n", err_str) } solution := VecFromGSL(csolution) val, solveErr := fn.F(solution) if solveErr != nil || val.AbsMax() > epsAbs { return nil, fmt.Errorf("solution is inaccurate; absolute error = %v", val) } C.gsl_vector_free(csolution) C.gsl_vector_free(cstart) return solution, nil }
// Interface to gsl_integration_qags: "adaptive integration with [integrable] // singularities". Integrate f from a to b and return the value of the // integral and the absolute error. func Qags(fn func(float64) float64, a, b, epsabs, epsrel float64) (result, absErr float64, err error) { cfn := unsafe.Pointer(&fn) C_result, C_absErr := C.double(0.0), C.double(0.0) // guard against panics during integration defer func() { if x := recover(); x != nil { result = 0.0 absErr = 0.0 err = x.(error) } }() // perform integration C_err := C.gslQags(cfn, C.double(a), C.double(b), C.double(epsabs), C.double(epsrel), &C_result, &C_absErr) if C_err != C.GSL_SUCCESS { err_str := C.GoString(C.gsl_strerror(C_err)) return 0.0, 0.0, fmt.Errorf("error in Qags (GSL): %v\n", err_str) } result = float64(C_result) absErr = float64(C_absErr) return }
func (e *GSLError) Error() (what string) { str := C.gsl_strerror(e.code) what = C.GoString(str) return }
// const char * gsl_strerror (const GslError gsl_errno) func (ge GslError) String() string { return C.GoString(C.gsl_strerror(C.int(ge))) }
func (e Error) Error() string { return C.GoString(C.gsl_strerror(C.int(e))) }