// 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 }
// Return the value for vector c which best fits the linear model y = Xc. // X is a matrix given by its row vectors: each row corresponds to a y value; // columns within the row correspond to coefficients for parameters in c. func Linear(y vec.Vector, X []vec.Vector) vec.Vector { n := C.size_t(len(y)) // number of observations p := C.size_t(len(X[0])) // number of parameters c, gslY := C.gsl_vector_alloc(p), C.gsl_vector_alloc(n) cov, gslX := C.gsl_matrix_alloc(p, p), C.gsl_matrix_alloc(n, p) vecToGSL(y, gslY) matrixToGSL(X, gslX) chisq := C.double(0) work := C.gsl_multifit_linear_alloc(n, p) C.gsl_multifit_linear(gslX, gslY, c, cov, &chisq, work) C.gsl_multifit_linear_free(work) result := vecFromGSL(c) C.gsl_matrix_free(gslX) C.gsl_matrix_free(cov) C.gsl_vector_free(gslY) C.gsl_vector_free(c) return result }
// 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 }
//export fit_go_df func fit_go_df(x C.const_gsl_vector, fn unsafe.Pointer, J *C.gsl_matrix) C.int { gofn := (*FitData)(fn) gx := vecFromGSL(x) for i := 0; i < gofn.N; i++ { val, err := gofn.Df(gx, i) if err != nil { // same assumption as fit_go_f return C.GSL_EDOM } gslval := C.gsl_vector_alloc(x.size) vecToGSL(val, gslval) C.gsl_matrix_set_row(J, C.size_t(i), gslval) C.gsl_vector_free(gslval) } return C.GSL_SUCCESS }
// Return an ordered slice of the eigenvalues of sym, and a slice of the // eigenvectors in the same order. func (sym *SymmetricMatrix) Eigensystem() ([]float64, [][]float64) { originalSize := sym.length reduced, convert := sym.RemoveEmptyRows() size := C.size_t(reduced.length) eigenvalues := C.gsl_vector_alloc(size) eigenvectors := C.gsl_matrix_alloc(size, size) matrix := reduced.toMatrix() work := C.gsl_eigen_symmv_alloc(size) err := C.gsl_eigen_symmv(matrix, eigenvalues, eigenvectors, work) if err != 0 { // handle it } goEigenvalues := vectorToSlice(eigenvalues) goEigenvectors := matrixColumnsToSlices(eigenvectors) C.gsl_vector_free(eigenvalues) C.gsl_matrix_free(eigenvectors) C.gsl_matrix_free(matrix) C.gsl_eigen_symmv_free(work) retEigenvectors := InsertEmptyRows(goEigenvectors, convert, originalSize) return goEigenvalues, retEigenvectors }