/* FIXME */ double fd_amer_put(double spot, double strike, double r, double d, double vol, double expiry, int ssteps, int tsteps) { /* M needs to be even */ int M = ssteps + ssteps % 2; int N = tsteps; double ds = 2.0 * spot / M; double dt = expiry / N; double vv = vol * vol; double *prices, *x, res; gsl_vector *diag, *e, *f, *B; gsl_vector_view X; int i, step; if ((prices = ALLOC((M + 1) * sizeof (double))) == NULL) return 0.0; if ((x = ALLOC((M + 1) * sizeof (double))) == NULL) { FREE(prices); return 0.0; } for (i = 0; i <= M; ++i) prices[i] = i * ds; /* tridiagonal systems */ diag = gsl_vector_alloc(M + 1); gsl_vector_set(diag, 0, 1.0); for (i = 1; i < M; ++i) gsl_vector_set(diag, i, 1.0 + dt * (vv * i * i + r)); gsl_vector_set(diag, M, 1.0); e = gsl_vector_alloc(M); gsl_vector_set(e, 0, 0.0); for (i = 1; i < M; ++i) gsl_vector_set(e, i, 0.5 * i * dt * (-r + d - vv * i)); f = gsl_vector_alloc(M); for (i = 0; i < M - 1; ++i) gsl_vector_set(f, i, 0.5 * i * dt * (r - d - vv * i)); gsl_vector_set(f, M - 1, 0.0); B = gsl_vector_alloc(M + 1); for (i = 0; i <= M; ++i) gsl_vector_set(B, i, MAX(0.0, strike - prices[i])); X = gsl_vector_view_array(x, M + 1); gsl_linalg_solve_tridiag(diag, e, f, B, &X.vector); for (step = N - 1; step > 0; --step) { gsl_vector_memcpy(B, &X.vector); gsl_linalg_solve_tridiag(diag, e, f, B, &X.vector); for (i = 1; i < M; ++i) x[i] = MAX(x[i], strike - prices[i]); } res = x[M / 2]; gsl_vector_free(B); gsl_vector_free(f); gsl_vector_free(e); gsl_vector_free(diag); FREE(x); FREE(prices); return res; }
void GSLRunMyProgram(int N, double *A, double *X, FILE *output){ int i; gsl_vector * x = gsl_vector_alloc (N); gsl_vector * e = gsl_vector_alloc (N-1); gsl_vector * d = gsl_vector_alloc (N); gsl_vector * f = gsl_vector_alloc (N-1); gsl_vector * b = gsl_vector_alloc (N); for (i = 0; i < N; i++) { gsl_vector_set (b, i, X[i]); gsl_vector_set (d, i, A[1 + 3*i]); } for(i = 0; i < N-1; i++){ gsl_vector_set (e, i, A[2 + 3*i]); gsl_vector_set (f, i, A[3*(i+1)]); } clock_t startTime = clock(); gsl_linalg_solve_tridiag(d, e, f, b, x); fprintf(output, "%f\n", 1000*(double)(clock()-startTime)/(double)(CLOCKS_PER_SEC)); // for(i = 0; i < N; i++){ // printf("GSL x%i: %g\n", i, gsl_vector_get(x, i)); // } gsl_vector_free (x); gsl_vector_free (e); gsl_vector_free (d); gsl_vector_free (f); gsl_vector_free (b); return; }
CAMLprim value ml_gsl_linalg_solve_tridiag(value DIAG, value ABOVE, value BELOW, value B, value X) { _DECLARE_VECTOR5(DIAG, ABOVE, BELOW, B, X); _CONVERT_VECTOR5(DIAG, ABOVE, BELOW, B, X); gsl_linalg_solve_tridiag(&v_DIAG, &v_ABOVE, &v_BELOW, &v_B, &v_X); return Val_unit; }
/** * C++ version of gsl_linalg_solve_tridiag(). * @param diag A vector of diagonal elements * @param abovediag Off-diagonal vector (one element shorte than @c diag) * @param belowdiag Off-diagonal vector (one element shorte than @c diag) * @param b A vector * @param x A vector * @return Error code on failure */ inline int solve_tridiag( vector const& diag, vector const& abovediag, vector const& belowdiag, vector const& b, vector& x ){ return gsl_linalg_solve_tridiag( diag.get(), abovediag.get(), belowdiag.get(), b.get(), x.get() ); }