static void target_func(double* p, double *f, double* g, int n, void* data) { int i; lbfgsb_param *param = (lbfgsb_param*)data; double weight = 0, error = 0, consts = 0.0, consts2 = 0.0; double sum = 0.0; for(i = 0; i < param->moneyness_size; i++) { double x = param->log_moneyness[i]; double sig = param->quotes[i]; double var_vec = sig*sig; double var_cal = svi(p, x); error += exp(x*3.0) * pow(var_cal - var_vec, 2); consts += user_min(var_cal, 0.0) * -0.1; } // calculate constraints 1 consts = exp(user_max(p[1] * (1.0 + fabs(p[4])) * param->T - 4.0, 0.0) ) - 1.0; consts2= exp(consts) - 1.0; *f = error + consts + consts2; }
/************************************************************************* Internal linear regression subroutine *************************************************************************/ static void lrinternal(const ap::real_2d_array& xy, const ap::real_1d_array& s, int npoints, int nvars, int& info, linearmodel& lm, lrreport& ar) { ap::real_2d_array a; ap::real_2d_array u; ap::real_2d_array vt; ap::real_2d_array vm; ap::real_2d_array xym; ap::real_1d_array b; ap::real_1d_array sv; ap::real_1d_array t; ap::real_1d_array svi; ap::real_1d_array work; int i; int j; int k; int ncv; int na; int nacv; double r; double p; double epstol; lrreport ar2; int offs; linearmodel tlm; epstol = 1000; // // Check for errors in data // if( npoints<nvars||nvars<1 ) { info = -1; return; } for(i = 0; i <= npoints-1; i++) { if( ap::fp_less_eq(s(i),0) ) { info = -2; return; } } info = 1; // // Create design matrix // a.setbounds(0, npoints-1, 0, nvars-1); b.setbounds(0, npoints-1); for(i = 0; i <= npoints-1; i++) { r = 1/s(i); ap::vmove(&a(i, 0), &xy(i, 0), ap::vlen(0,nvars-1), r); b(i) = xy(i,nvars)/s(i); } // // Allocate W: // W[0] array size // W[1] version number, 0 // W[2] NVars (minus 1, to be compatible with external representation) // W[3] coefficients offset // lm.w.setbounds(0, 4+nvars-1); offs = 4; lm.w(0) = 4+nvars; lm.w(1) = lrvnum; lm.w(2) = nvars-1; lm.w(3) = offs; // // Solve problem using SVD: // // 0. check for degeneracy (different types) // 1. A = U*diag(sv)*V' // 2. T = b'*U // 3. w = SUM((T[i]/sv[i])*V[..,i]) // 4. cov(wi,wj) = SUM(Vji*Vjk/sv[i]^2,K=1..M) // // see $15.4 of "Numerical Recipes in C" for more information // t.setbounds(0, nvars-1); svi.setbounds(0, nvars-1); ar.c.setbounds(0, nvars-1, 0, nvars-1); vm.setbounds(0, nvars-1, 0, nvars-1); if( !rmatrixsvd(a, npoints, nvars, 1, 1, 2, sv, u, vt) ) { info = -4; return; } if( ap::fp_less_eq(sv(0),0) ) { // // Degenerate case: zero design matrix. // for(i = offs; i <= offs+nvars-1; i++) { lm.w(i) = 0; } ar.rmserror = lrrmserror(lm, xy, npoints); ar.avgerror = lravgerror(lm, xy, npoints); ar.avgrelerror = lravgrelerror(lm, xy, npoints); ar.cvrmserror = ar.rmserror; ar.cvavgerror = ar.avgerror; ar.cvavgrelerror = ar.avgrelerror; ar.ncvdefects = 0; ar.cvdefects.setbounds(0, nvars-1); ar.c.setbounds(0, nvars-1, 0, nvars-1); for(i = 0; i <= nvars-1; i++) { for(j = 0; j <= nvars-1; j++) { ar.c(i,j) = 0; } } return; } if( ap::fp_less_eq(sv(nvars-1),epstol*ap::machineepsilon*sv(0)) ) { // // Degenerate case, non-zero design matrix. // // We can leave it and solve task in SVD least squares fashion. // Solution and covariance matrix will be obtained correctly, // but CV error estimates - will not. It is better to reduce // it to non-degenerate task and to obtain correct CV estimates. // for(k = nvars; k >= 1; k--) { if( ap::fp_greater(sv(k-1),epstol*ap::machineepsilon*sv(0)) ) { // // Reduce // xym.setbounds(0, npoints-1, 0, k); for(i = 0; i <= npoints-1; i++) { for(j = 0; j <= k-1; j++) { r = ap::vdotproduct(&xy(i, 0), &vt(j, 0), ap::vlen(0,nvars-1)); xym(i,j) = r; } xym(i,k) = xy(i,nvars); } // // Solve // lrinternal(xym, s, npoints, k, info, tlm, ar2); if( info!=1 ) { return; } // // Convert back to un-reduced format // for(j = 0; j <= nvars-1; j++) { lm.w(offs+j) = 0; } for(j = 0; j <= k-1; j++) { r = tlm.w(offs+j); ap::vadd(&lm.w(offs), &vt(j, 0), ap::vlen(offs,offs+nvars-1), r); } ar.rmserror = ar2.rmserror; ar.avgerror = ar2.avgerror; ar.avgrelerror = ar2.avgrelerror; ar.cvrmserror = ar2.cvrmserror; ar.cvavgerror = ar2.cvavgerror; ar.cvavgrelerror = ar2.cvavgrelerror; ar.ncvdefects = ar2.ncvdefects; ar.cvdefects.setbounds(0, nvars-1); for(j = 0; j <= ar.ncvdefects-1; j++) { ar.cvdefects(j) = ar2.cvdefects(j); } ar.c.setbounds(0, nvars-1, 0, nvars-1); work.setbounds(1, nvars); matrixmatrixmultiply(ar2.c, 0, k-1, 0, k-1, false, vt, 0, k-1, 0, nvars-1, false, 1.0, vm, 0, k-1, 0, nvars-1, 0.0, work); matrixmatrixmultiply(vt, 0, k-1, 0, nvars-1, true, vm, 0, k-1, 0, nvars-1, false, 1.0, ar.c, 0, nvars-1, 0, nvars-1, 0.0, work); return; } } info = -255; return; } for(i = 0; i <= nvars-1; i++) { if( ap::fp_greater(sv(i),epstol*ap::machineepsilon*sv(0)) ) { svi(i) = 1/sv(i); } else { svi(i) = 0; } } for(i = 0; i <= nvars-1; i++) { t(i) = 0; } for(i = 0; i <= npoints-1; i++) { r = b(i); ap::vadd(&t(0), &u(i, 0), ap::vlen(0,nvars-1), r); } for(i = 0; i <= nvars-1; i++) { lm.w(offs+i) = 0; } for(i = 0; i <= nvars-1; i++) { r = t(i)*svi(i); ap::vadd(&lm.w(offs), &vt(i, 0), ap::vlen(offs,offs+nvars-1), r); } for(j = 0; j <= nvars-1; j++) { r = svi(j); ap::vmove(vm.getcolumn(j, 0, nvars-1), vt.getrow(j, 0, nvars-1), r); } for(i = 0; i <= nvars-1; i++) { for(j = i; j <= nvars-1; j++) { r = ap::vdotproduct(&vm(i, 0), &vm(j, 0), ap::vlen(0,nvars-1)); ar.c(i,j) = r; ar.c(j,i) = r; } } // // Leave-1-out cross-validation error. // // NOTATIONS: // A design matrix // A*x = b original linear least squares task // U*S*V' SVD of A // ai i-th row of the A // bi i-th element of the b // xf solution of the original LLS task // // Cross-validation error of i-th element from a sample is // calculated using following formula: // // ERRi = ai*xf - (ai*xf-bi*(ui*ui'))/(1-ui*ui') (1) // // This formula can be derived from normal equations of the // original task // // (A'*A)x = A'*b (2) // // by applying modification (zeroing out i-th row of A) to (2): // // (A-ai)'*(A-ai) = (A-ai)'*b // // and using Sherman-Morrison formula for updating matrix inverse // // NOTE 1: b is not zeroed out since it is much simpler and // does not influence final result. // // NOTE 2: some design matrices A have such ui that 1-ui*ui'=0. // Formula (1) can't be applied for such cases and they are skipped // from CV calculation (which distorts resulting CV estimate). // But from the properties of U we can conclude that there can // be no more than NVars such vectors. Usually // NVars << NPoints, so in a normal case it only slightly // influences result. // ncv = 0; na = 0; nacv = 0; ar.rmserror = 0; ar.avgerror = 0; ar.avgrelerror = 0; ar.cvrmserror = 0; ar.cvavgerror = 0; ar.cvavgrelerror = 0; ar.ncvdefects = 0; ar.cvdefects.setbounds(0, nvars-1); for(i = 0; i <= npoints-1; i++) { // // Error on a training set // r = ap::vdotproduct(&xy(i, 0), &lm.w(offs), ap::vlen(0,nvars-1)); ar.rmserror = ar.rmserror+ap::sqr(r-xy(i,nvars)); ar.avgerror = ar.avgerror+fabs(r-xy(i,nvars)); if( ap::fp_neq(xy(i,nvars),0) ) { ar.avgrelerror = ar.avgrelerror+fabs((r-xy(i,nvars))/xy(i,nvars)); na = na+1; } // // Error using fast leave-one-out cross-validation // p = ap::vdotproduct(&u(i, 0), &u(i, 0), ap::vlen(0,nvars-1)); if( ap::fp_greater(p,1-epstol*ap::machineepsilon) ) { ar.cvdefects(ar.ncvdefects) = i; ar.ncvdefects = ar.ncvdefects+1; continue; } r = s(i)*(r/s(i)-b(i)*p)/(1-p); ar.cvrmserror = ar.cvrmserror+ap::sqr(r-xy(i,nvars)); ar.cvavgerror = ar.cvavgerror+fabs(r-xy(i,nvars)); if( ap::fp_neq(xy(i,nvars),0) ) { ar.cvavgrelerror = ar.cvavgrelerror+fabs((r-xy(i,nvars))/xy(i,nvars)); nacv = nacv+1; } ncv = ncv+1; } if( ncv==0 ) { // // Something strange: ALL ui are degenerate. // Unexpected... // info = -255; return; } ar.rmserror = sqrt(ar.rmserror/npoints); ar.avgerror = ar.avgerror/npoints; if( na!=0 ) { ar.avgrelerror = ar.avgrelerror/na; } ar.cvrmserror = sqrt(ar.cvrmserror/ncv); ar.cvavgerror = ar.cvavgerror/ncv; if( nacv!=0 ) { ar.cvavgrelerror = ar.cvavgrelerror/nacv; } }