/** * Finds a path which traces the 0 contour of f, traversing from A to B as a single d2<sbasis>. * degmax specifies the degree (degree = 2*degmax-1, so a degmax of 2 generates a cubic fit). * The algorithm is based on dividing out derivatives at each end point and does not use the curvature for fitting. * It is less accurate than sb2d_cubic_solve, although this may be fixed in the future. */ D2<SBasis> sb2dsolve(SBasis2d const &f, Geom::Point const &A, Geom::Point const &B, unsigned degmax){ //g_warning("check f(A)= %f = f(B) = %f =0!", f.apply(A[X],A[Y]), f.apply(B[X],B[Y])); SBasis2d dfdu = partial_derivative(f, 0); SBasis2d dfdv = partial_derivative(f, 1); Geom::Point dfA(dfdu.apply(A[X],A[Y]),dfdv.apply(A[X],A[Y])); Geom::Point dfB(dfdu.apply(B[X],B[Y]),dfdv.apply(B[X],B[Y])); Geom::Point nA = dfA/(dfA[X]*dfA[X]+dfA[Y]*dfA[Y]); Geom::Point nB = dfB/(dfB[X]*dfB[X]+dfB[Y]*dfB[Y]); D2<SBasis>result(SBasis(degmax, Linear()), SBasis(degmax, Linear())); double fact_k=1; double sign = 1.; for(int dim = 0; dim < 2; dim++) result[dim][0] = Linear(A[dim],B[dim]); for(unsigned k=1; k<degmax; k++){ // these two lines make the solutions worse! //fact_k *= k; //sign = -sign; SBasis f_on_curve = compose(f,result); Linear reste = f_on_curve[k]; double ax = -reste[0]/fact_k*nA[X]; double ay = -reste[0]/fact_k*nA[Y]; double bx = -sign*reste[1]/fact_k*nB[X]; double by = -sign*reste[1]/fact_k*nB[Y]; result[X][k] = Linear(ax,bx); result[Y][k] = Linear(ay,by); //sign *= 3; } return result; }
SBasis2d partial_derivative(SBasis2d const &f, int dim) { SBasis2d result; for(unsigned i = 0; i < f.size(); i++) { result.push_back(Linear2d(0,0,0,0)); } result.us = f.us; result.vs = f.vs; for(unsigned i = 0; i < f.us; i++) { for(unsigned j = 0; j < f.vs; j++) { Linear2d lin = f.index(i,j); Linear2d dlin(lin[1+dim]-lin[0], lin[1+2*dim]-lin[dim], lin[3-dim]-lin[2*(1-dim)], lin[3]-lin[2-dim]); result[i+j*result.us] += dlin; unsigned di = dim?j:i; if (di>=1){ float motpi = dim?-1:1; Linear2d ds_lin_low( lin[0], -motpi*lin[1], motpi*lin[2], -lin[3] ); result[(i+dim-1)+(j-dim)*result.us] += di*ds_lin_low; Linear2d ds_lin_hi( lin[1+dim]-lin[0], lin[1+2*dim]-lin[dim], lin[3]-lin[2-dim], lin[3-dim]-lin[2-dim] ); result[i+j*result.us] += di*ds_lin_hi; } } } return result; }
void v_coef(SBasis2d f, unsigned deg, SBasis &a, SBasis &b) { a = SBasis(f.us, Linear()); b = SBasis(f.us, Linear()); for (unsigned u=0; u<f.us; u++){ a[u] = Linear(f.index(deg,u)[0], f.index(deg,u)[1]); b[u] = Linear(f.index(deg,u)[2], f.index(deg,u)[3]); } }
//see a sb2d as an sb of u with coef in sbasis of v. void u_coef(SBasis2d f, unsigned deg, SBasis &a, SBasis &b) { a = SBasis(f.vs, Linear()); b = SBasis(f.vs, Linear()); for (unsigned v=0; v<f.vs; v++){ a[v] = Linear(f.index(deg,v)[0], f.index(deg,v)[2]); b[v] = Linear(f.index(deg,v)[1], f.index(deg,v)[3]); } }
void v_coef(SBasis2d f, unsigned deg, SBasis &a, SBasis &b) { a = SBasis(); b = SBasis(); for (unsigned u=0; u<f.us; u++){ a.push_back(Linear(f.index(deg,u)[0], f.index(deg,u)[1])); b.push_back(Linear(f.index(deg,u)[2], f.index(deg,u)[3])); } }
//see a sb2d as an sb of u with coef in sbasis of v. void u_coef(SBasis2d f, unsigned deg, SBasis &a, SBasis &b) { a = SBasis(); b = SBasis(); for (unsigned v=0; v<f.vs; v++){ a.push_back(Linear(f.index(deg,v)[0], f.index(deg,v)[2])); b.push_back(Linear(f.index(deg,v)[1], f.index(deg,v)[3])); } }
SBasis extract_u(SBasis2d const &a, double u) { SBasis sb(a.vs, Linear()); double s = u*(1-u); for(unsigned vi = 0; vi < a.vs; vi++) { double sk = 1; Linear bo(0,0); for(unsigned ui = 0; ui < a.us; ui++) { bo += (extract_u(a.index(ui, vi), u))*sk; sk *= s; } sb[vi] = bo; } return sb; }
SBasis extract_v(SBasis2d const &a, double v) { SBasis sb(a.us, Linear()); double s = v*(1-v); for(unsigned ui = 0; ui < a.us; ui++) { double sk = 1; Linear bo(0,0); for(unsigned vi = 0; vi < a.vs; vi++) { bo += (extract_v(a.index(ui, vi), v))*sk; sk *= s; } sb[ui] = bo; } return sb; }
virtual void draw(cairo_t *cr, std::ostringstream *notify, int width, int height, bool save, std::ostringstream *timer_stream) { double slider_top = width/4.; double slider_bot = width*3./4.; double slider_margin = width/8.; if(hand.pts.empty()) { hand.pts.push_back(Geom::Point(width*3./16., 3*width/4.)); hand.pts.push_back(hand.pts[0] + Geom::Point(width/2., 0)); hand.pts.push_back(hand.pts[0] + Geom::Point(width/8., -width/12.)); hand.pts.push_back(hand.pts[0] + Geom::Point(0,-width/4.)); hand.pts.push_back(Geom::Point(slider_margin,slider_bot)); hand.pts.push_back(Geom::Point(width-slider_margin,slider_top)); } hand.pts[4][X] = slider_margin; if (hand.pts[4][Y]<slider_top) hand.pts[4][Y] = slider_top; if (hand.pts[4][Y]>slider_bot) hand.pts[4][Y] = slider_bot; hand.pts[5][X] = width-slider_margin; if (hand.pts[5][Y]<slider_top) hand.pts[5][Y] = slider_top; if (hand.pts[5][Y]>slider_bot) hand.pts[5][Y] = slider_bot; double tA = (slider_bot-hand.pts[4][Y])/(slider_bot-slider_top); double tB = (slider_bot-hand.pts[5][Y])/(slider_bot-slider_top); cairo_move_to(cr,Geom::Point(slider_margin,slider_bot)); cairo_line_to(cr,Geom::Point(slider_margin,slider_top)); cairo_move_to(cr,Geom::Point(width-slider_margin,slider_bot)); cairo_line_to(cr,Geom::Point(width-slider_margin,slider_top)); cairo_set_line_width(cr,.5); cairo_set_source_rgba (cr, 0., 0.3, 0., 1.); cairo_stroke(cr); Frame frame; frame.O = hand.pts[0];// frame.x = hand.pts[1]-hand.pts[0];// frame.y = hand.pts[2]-hand.pts[0];// frame.z = hand.pts[3]-hand.pts[0];// /* SBasis2d f = y_x2(); D2<SBasis> true_solution(Linear(0,1),Linear(0,1)); true_solution[Y].push_back(Linear(-1,-1)); SBasis zero = SBasis(Linear(0.)); Geom::Point A = true_solution(tA); Geom::Point B = true_solution(tB); */ SBasis2d f = x2_plus_y2_1(); D2<Piecewise<SBasis> > true_solution; true_solution[X] = cos(SBasis(Linear(0,3.141592/2))); true_solution[Y] = sin(SBasis(Linear(0,3.141592/2))); Piecewise<SBasis> zero = Piecewise<SBasis>(SBasis(Linear(0.))); //Geom::Point A(cos(tA*M_PI/2), sin(tA*M_PI/2));// = true_solution(tA); //Geom::Point B(cos(tB*M_PI/2), sin(tB*M_PI/2));// = true_solution(tB); Geom::Point A = true_solution(tA); Geom::Point B = true_solution(tB); Point dA(-sin(tA*M_PI/2), cos(tA*M_PI/2)); Geom::Point dB(-sin(tB*M_PI/2), cos(tB*M_PI/2)); SBasis2d dfdu = partial_derivative(f, 0); SBasis2d dfdv = partial_derivative(f, 1); Geom::Point dfA(dfdu.apply(A[X],A[Y]),dfdv.apply(A[X],A[Y])); Geom::Point dfB(dfdu.apply(B[X],B[Y]),dfdv.apply(B[X],B[Y])); dA = rot90(dfA); dB = rot90(dfB); plot3d(cr,Linear(0,1),Linear(0,0),Linear(0,0),frame); plot3d(cr,Linear(0,1),Linear(1,1),Linear(0,0),frame); plot3d(cr,Linear(0,0),Linear(0,1),Linear(0,0),frame); plot3d(cr,Linear(1,1),Linear(0,1),Linear(0,0),frame); cairo_set_line_width(cr,.2); cairo_set_source_rgba (cr, 0., 0., 0., 1.); cairo_stroke(cr); plot3d_top(cr,f,frame); cairo_set_line_width(cr,1); cairo_set_source_rgba (cr, .5, 0.5, 0.5, 1.); cairo_stroke(cr); plot3d(cr,f,frame); cairo_set_line_width(cr,.2); cairo_set_source_rgba (cr, .5, 0.5, 0.5, 1.); cairo_stroke(cr); plot3d(cr, true_solution[X], true_solution[Y], zero, frame); cairo_set_line_width(cr,.5); cairo_set_source_rgba (cr, 0., 0., 0., 1.); cairo_stroke(cr); double error; for(int degree = 2; degree < 2; degree++) { D2<SBasis> zeroset = sb2dsolve(f,A,B,degree); plot3d(cr, zeroset[X], zeroset[Y], SBasis(Linear(0.)),frame); cairo_set_line_width(cr,1); cairo_set_source_rgba (cr, 0.9, 0., 0., 1.); cairo_stroke(cr); SBasis comp = compose(f,zeroset); plot3d(cr, zeroset[X], zeroset[Y], comp, frame); cairo_set_source_rgba (cr, 0.7, 0., 0.7, 1.); cairo_stroke(cr); //Fix Me: bounds_exact does not work here?!?! Interval bounds = *bounds_fast(comp); error = (bounds.max()>-bounds.min() ? bounds.max() : -bounds.min() ); } if (1) { bits_n_bobs par = {&f, A, B, dA, dB}; bits_n_bobs* bnb = ∥ std::cout << f[0] << "= intial f \n"; const gsl_multimin_fminimizer_type *T = gsl_multimin_fminimizer_nmsimplex; gsl_multimin_fminimizer *s = NULL; gsl_vector *ss, *x; gsl_multimin_function minex_func; size_t iter = 0; int status; double size; /* Starting point */ x = gsl_vector_alloc (2); gsl_vector_set (x, 0, 0.552); // magic number for quarter circle gsl_vector_set (x, 1, 0.552); /* Set initial step sizes to 1 */ ss = gsl_vector_alloc (2); gsl_vector_set_all (ss, 0.1); /* Initialize method and iterate */ minex_func.n = 2; minex_func.f = &my_f; minex_func.params = (void *)∥ s = gsl_multimin_fminimizer_alloc (T, 2); gsl_multimin_fminimizer_set (s, &minex_func, x, ss); do { iter++; status = gsl_multimin_fminimizer_iterate(s); if (status) break; size = gsl_multimin_fminimizer_size (s); status = gsl_multimin_test_size (size, 1e-7); if (status == GSL_SUCCESS) { printf ("converged to minimum at\n"); } } while (status == GSL_CONTINUE && iter < 100); printf ("%5lu %g %gf f() = %g size = %g\n", iter, gsl_vector_get (s->x, 0), gsl_vector_get (s->x, 1), s->fval, size); { double x = gsl_vector_get(s->x, 0); double y = gsl_vector_get(s->x, 1); Bezier b0(bnb->B[0], bnb->B[0]+bnb->dB[0]*x, bnb->A[0]+bnb->dA[0]*y, bnb->A[0]); Bezier b1(bnb->B[1], bnb->B[1]+bnb->dB[1]*x, bnb->A[1]+bnb->dA[1]*y, bnb->A[1]); D2<SBasis> zeroset(b0.toSBasis(), b1.toSBasis()); plot3d(cr, zeroset[X], zeroset[Y], SBasis(Linear(0.)),frame); cairo_set_line_width(cr,1); cairo_set_source_rgba (cr, 0.9, 0., 0., 1.); cairo_stroke(cr); SBasis comp = compose(f,zeroset); plot3d(cr, zeroset[X], zeroset[Y], comp, frame); cairo_set_source_rgba (cr, 0.7, 0., 0.7, 1.); cairo_stroke(cr); //Fix Me: bounds_exact does not work here?!?! Interval bounds = *bounds_fast(comp); error = (bounds.max()>-bounds.min() ? bounds.max() : -bounds.min() ); } gsl_vector_free(x); gsl_vector_free(ss); gsl_multimin_fminimizer_free (s); } *notify << "Gray: f-graph and true solution,\n"; *notify << "Red: solver solution,\n"; *notify << "Purple: value of f over solver solution.\n"; *notify << " error: "<< error <<".\n"; Toy::draw(cr, notify, width, height, save,timer_stream); }