double struve(double v, double x) { double y, ya, f, g, h, t; double onef2err, threef0err; f = floor(v); if ((v < 0) && (v - f == 0.5)) { y = jv(-v, x); f = 1.0 - f; g = 2.0 * floor(f / 2.0); if (g != f) y = -y; return(y); } t = 0.25 * x * x; f = fabs(x); g = 1.5 * fabs(v); if ((f > 30.0) && (f > g)) { onef2err = 1.0e38; y = 0.0; } else { y = onef2(1.0, 1.5, 1.5 + v, -t, &onef2err); } if ((f < 18.0) || (x < 0.0)) { threef0err = 1.0e38; ya = 0.0; } else { ya = threef0(1.0, 0.5, 0.5 - v, -1.0 / t, &threef0err); } f = sqrt(PI); h = pow(0.5 * x, v - 1.0); if (onef2err <= threef0err) { g = gam(v + 1.5); y = y * h * t / (0.5 * f * g); return(y); } else { g = gam(v + 0.5); ya = ya * h / (f * g); ya = ya + yv(v, x); return(ya); } }
vector<float> tridag(const vector<float> &a,const vector<float> &b, const vector<float> &c, const vector<float> &r) { vector<float> u(b.size(),0.0); vector<float> gam(b.size()); float bet; if(FCMP(b[0],0.0)) { cout << "Error - matrix[0][0] == 0.0 - try rewriting eqns. as a set of order n-1 with u2 trivually elimianted..." << endl; return u; } u[0] = r[0]/(bet=b[0]); for(unsigned long int j = 1; j<b.size(); j++) { gam[j] = c[j-1]/bet; bet = b[j]-a[j]*gam[j]; if(FCMP(bet,0.0)) { cout << "Error - cannot solve tridag system.\n" << endl; return u; } u[j] = (r[j]-a[j]*u[j-1])/bet; } for(unsigned long int i = b.size()-2; i>=0;i--) { u[i]-=gam[i+1]*u[i+1]; if(i==0) { break; } } return u; }
double get_freq(double temper) { double rm = 0.5*mass[0]; double cr = 2.0 * sqrt(2.0*K*temper/(rm*PI)); double sigma = PI*diam[0]*diam[0]; double fr = conc[0]*sigma*pow(cr, 2.0*viscos - 1)*(2.0/sqrt(PI))*gam(2.5 - viscos)*pow(2.0*K*temper/rm,1.0-viscos); return fr; }
int Cvode::solvex_thread_part1(double* b, NrnThread* nt){ //printf("Cvode::solvex_thread %d t=%g t_=%g\n", nt->id, nt->t, t_); //printf("Cvode::solvex_thread %d %g\n", nt->id, gam()); //printf("\tenter b\n"); //for (int i=0; i < neq_; ++i) { printf("\t\t%d %g\n", i, b[i]);} int i; CvodeThreadData& z = ctd_[nt->id]; nt->cj = 1./gam(); nt->_dt = gam(); if (z.nvsize_ == 0) { return 0; } lhs(nt); // special version for cvode. scatter_ydot(b, nt->id); nrn_mul_capacity(nt, z.cmlcap_->ml); for (i=0; i < z.no_cap_count_; ++i) { NODERHS(z.no_cap_node_[i]) = 0.; } // solve it nrn_multisplit_triang(nt); return 0; }
//============================================================================== //! simultaneous tridiagonal system //============================================================================== static inline void vertex_tridiag(const array<Real> &a, const array<Real> &b, const array<Real> &c, const array<Vertex> &r, array<Vertex> &u, const size_t n) { const Vertex org(0,0); assert(n<=a.size()); assert(n<=b.size()); assert(n<=c.size()); assert(n<=r.size()); assert(n<=u.size()); assert(Fabs(b[1])>0); Vertex bet; vector<Vertex> gam(n,org); u[1]=r[1]/(bet.x=bet.y=b[1]); for(size_t j=2;j<=n;j++) { Vertex &gam_j = gam[j]; const Real c_jm = c[j-1]; gam_j.x = c_jm/bet.x; gam_j.y = c_jm/bet.y; const Real b_j = b[j]; const Real a_j = a[j]; bet.x = b_j - a_j * gam_j.x; bet.y = b_j - a_j * gam_j.y; if ( Fabs(bet.x) <= 0 || Fabs(bet.y) <= 0 ) throw exception("Error 2 in tridag"); const Vertex &r_j = r[j]; Vertex &u_j = u[j]; const Vertex &u_jm = u[j-1]; u_j.x = (r_j.x - a_j * u_jm.x) / bet.x; u_j.y = (r_j.y - a_j * u_jm.y) / bet.y; } for(size_t j=(n-1);j>=1;j--) { Vertex &u_j = u[j]; const Vertex &u_jp = u[j+1]; const Vertex &gam_jp = gam[j+1]; u_j.x -= gam_jp.x * u_jp.x; u_j.y -= gam_jp.y * u_jp.y; } }
int Cvode::solvex_thread(double* b, double* y, NrnThread* nt){ //printf("Cvode::solvex_thread %d t=%g t_=%g\n", nt->id, nt->t, t_); //printf("Cvode::solvex_thread %d %g\n", nt->id, gam()); //printf("\tenter b\n"); //for (int i=0; i < neq_; ++i) { printf("\t\t%d %g\n", i, b[i]);} int i; CvodeThreadData& z = CTD(nt->id); nt->cj = 1./gam(); nt->_dt = gam(); if (z.nvsize_ == 0) { return 0; } lhs(nt); // special version for cvode. scatter_ydot(b, nt->id); nrn_mul_capacity(nt, z.cmlcap_->ml); for (i=0; i < z.no_cap_count_; ++i) { NODERHS(z.no_cap_node_[i]) = 0.; } // solve it #if PARANEURON if (nrn_multisplit_solve_) { (*nrn_multisplit_solve_)(); }else #endif { triang(nt); bksub(nt); } //for (i=0; i < v_node_count; ++i) { // printf("%d rhs %d %g t=%g\n", nrnmpi_myid, i, VEC_RHS(i), t); //} if (ncv_->stiff() == 2) { solvemem(nt); }else{ // bug here should multiply by gam } gather_ydot(b, nt->id); //printf("\texit b\n"); //for (i=0; i < neq_; ++i) { printf("\t\t%d %g\n", i, b[i]);} return 0; }
void NR::tridag(Vec_I_DP &a, Vec_I_DP &b, Vec_I_DP &c, Vec_I_DP &r, Vec_O_DP &u) { int j; DP bet; int n=a.size(); Vec_DP gam(n); if (b[0] == 0.0) nrerror("Error 1 in tridag"); u[0]=r[0]/(bet=b[0]); for (j=1; j<n; j++) { gam[j]=c[j-1]/bet; bet=b[j]-a[j]*gam[j]; if (bet == 0.0) nrerror("Error 2 in tridag"); u[j]=(r[j]-a[j]*u[j-1])/bet; } for (j=(n-2); j>=0; j--) u[j] -= gam[j+1]*u[j+1]; }
void StreamPower::Tridag(std::vector<double>& a, std::vector<double>& b, std::vector<double>& c, std::vector<double>& r, std::vector<double>& u, int n) { int j; double bet; std::vector<double> gam(n); u[0] = r[0] / (bet = b[0]); for (j = 1; j < n; j++) { gam[j] = c[j - 1] / bet; bet = b[j] - a[j] * gam[j]; u[j] = (r[j] - a[j] * u[j - 1]) / bet; } for (j = (n - 2); j > 0; j--) { u[j] -= gam[j + 1] * u[j + 1]; } }
static double hy1f1a(double a, double b, double x, double *err) { double h1, h2, t, u, temp, acanc, asum, err1, err2; if (x == 0) { acanc = 1.0; asum = MAXNUM; goto adone; } temp = log(fabs(x)); t = x + temp * (a - b); u = -temp * a; if (b > 0) { temp = lgam(b); t += temp; u += temp; } h1 = hyp2f0(a, a - b + 1, -1.0 / x, 1, &err1); temp = exp(u) / gam(b - a); h1 *= temp; err1 *= temp; h2 = hyp2f0(b - a, 1.0 - a, 1.0 / x, 2, &err2); if (a < 0) temp = exp(t) / gam(a); else temp = exp(t - lgam(a)); h2 *= temp; err2 *= temp; if (x < 0.0) asum = h1; else asum = h2; acanc = fabs(err1) + fabs(err2); if (b < 0) { temp = gam(b); asum *= temp; acanc *= fabs(temp); } if (asum != 0.0) acanc /= fabs(asum); acanc *= 30.0; /* fudge factor, since error of asymptotic formula * often seems this much larger than advertised */ adone: *err = acanc; return(asum); }
int main() { // Observed sequence typedef float T; std::vector<T> observed, initial, tmp; std::vector< std::vector<T> > transition, emission, results; std::string obs = "010000000010000100001000000000"; make_vector(observed, obs); std::copy(observed.begin(), observed.end(), std::ostream_iterator<T>(std::cout, " ")); std::cout << std::endl << "Length = " << observed.size() << std::endl; // Initial state probabilities initial.push_back(0.5), initial.push_back(0.5); // Transitional probabilities tmp.clear(); tmp.push_back(0.9), tmp.push_back(0.1); transition.push_back(tmp); tmp.clear(); tmp.push_back(0.5), tmp.push_back(0.5); transition.push_back(tmp); // Emission probabilities tmp.clear(); tmp.push_back(0.2), tmp.push_back(0.3), tmp.push_back(0.5); emission.push_back(tmp); tmp.clear(); tmp.push_back(0.5), tmp.push_back(0.2), tmp.push_back(0.3); emission.push_back(tmp); dolog(initial, transition, emission); // Test full forward std::cout << "Full Forward" << std::endl; std::size_t index = observed.size(); results.resize(initial.size()); for ( std::size_t i = 0; i < results.size(); ++i ) results[i].resize(index); ci::hmm::forward_full(observed, initial, transition, emission, index, results); for ( std::size_t i = 0; i < results.size(); ++i ) { for ( std::size_t j = 0; j < results[i].size(); ++j ) std::cout << results[i][j] << "\t"; std::cout << std::endl; } // for // Test indexed forward std::cout << "Indexed Forward" << std::endl; std::vector<T> ok(initial.size(), 0); ci::hmm::forward_index(observed, initial, transition, emission, 1, ok); std::copy(ok.begin(), ok.end(), std::ostream_iterator<T>(std::cout, "\t")); std::cout << std::endl; // Test next forward ok.clear(); ok.resize(initial.size(), 0); for ( std::size_t i = 1; i <= observed.size(); ++i ) { std::cout << "Next Forward (" << i << ")" << std::endl; ci::hmm::forward_next(observed, initial, transition, emission, i, ok); std::copy(ok.begin(), ok.end(), std::ostream_iterator<T>(std::cout, "\t")); std::cout << std::endl; } // Test backward std::cout << "Full Backward" << std::endl; results.clear(); results.resize(initial.size()); for ( std::size_t i = 0; i < results.size(); ++i ) results[i].resize(observed.size(), 0); index = 1; ci::hmm::backward_full(observed, initial, transition, emission, index, results); for ( std::size_t i = 0; i < results.size(); ++i ) { for ( std::size_t j = 0; j < results[i].size(); ++j ) std::cout << results[i][j] << "\t"; std::cout << std::endl; } // for // Test indexed backward std::cout << "Indexed Backward" << std::endl; ok.clear(); ok.resize(initial.size()); ci::hmm::backward_index(observed, initial, transition, emission, index, ok); std::copy(ok.begin(), ok.end(), std::ostream_iterator<T>(std::cout, "\t")); std::cout << std::endl; // Test next backward ok.clear(); ok.resize(initial.size(), 0); for ( std::size_t i = observed.size(); i > 0; --i ) { std::cout << "Next Backward (" << i << ")" << std::endl; ci::hmm::backward_next(observed, initial, transition, emission, i, ok); std::copy(ok.begin(), ok.end(), std::ostream_iterator<T>(std::cout, "\t")); std::cout << std::endl; } typedef std::vector<T> FOO; FOO const* foo; ci::hmm::details::BackCache< FOO, FOO, std::vector<FOO>, std::vector<FOO>, T > backcheaterA(observed, initial, transition, emission); for ( std::size_t i = 0; i < observed.size(); ++i ) { std::cout << "Cheat Backward->Forward (" << i << ")" << std::endl; foo = backcheaterA.Next(); std::copy(foo->begin(), foo->end(), std::ostream_iterator<T>(std::cout, "\t")); std::cout << std::endl; } // Test extended next backward std::vector< std::vector<T> > dummy(initial.size()); for ( std::size_t i = 0; i < dummy.size(); ++i ) dummy[i] = std::vector<T>(initial.size(), 0); for ( std::size_t i = observed.size(); i > 0; --i ) { std::cout << "(Ext) Next Backward (" << i << ")" << std::endl; ci::hmm::backward_enext(observed, initial, transition, emission, i, dummy); for ( std::size_t j = 0; j < dummy.size(); ++j ) { for ( std::size_t k = 0; k < dummy[j].size(); ++k ) std::cout << dummy[k][j] << "\t"; std::cout << std::endl; } // for std::cout << std::endl; } // for // Problem 1 float ans1 = ci::hmm::evalp(observed, initial, transition, emission); std::cout << "Answer to problem 1: " << ans1 << std::endl; // Problem 2 // Test viterbi std::cout << "Viterbi answer to problem 2" << std::endl; std::ostream_iterator<T> os(std::cout, "\t"); ci::hmm::viterbi(observed, initial, transition, emission, os); std::cout << std::endl; // Test gamma std::cout << "Testing Gamma" << std::endl; results.clear(); results.resize(initial.size()); for ( std::size_t i = 0; i < results.size(); ++i ) results[i].resize(observed.size(), 0); ci::hmm::gamma_m_full(observed, initial, transition, emission, results); for ( std::size_t i = 0; i < results.size(); ++i ) { for ( std::size_t j = 0; j < results[i].size(); ++j ) std::cout << results[i][j] << "\t"; std::cout << std::endl; } // for std::cout << "New Gamma" << std::endl; std::vector<T> alpha(initial.size(), 0), beta(alpha.size(), 0), gam(alpha.size(), 0); ci::hmm::details::BackCache< FOO, FOO, std::vector<FOO>, std::vector<FOO>, T > backcheaterB(observed, initial, transition, emission); for ( std::size_t i = 1; i <= observed.size(); ++i ) { std::vector<T> const* foo = backcheaterB.Next(); ci::hmm::gamma(observed, initial, transition, emission, i, *foo, alpha, gam); delete foo; std::copy(gam.begin(), gam.end(), std::ostream_iterator<T>(std::cout, "\t")); std::cout << std::endl; } // for // Test xi std::cout << "Testing xi" << std::endl; std::vector< std::vector< std::vector<T> > > v(initial.size()); for ( std::size_t i = 0; i < v.size(); ++i ) { v[i].resize(initial.size()); for ( std::size_t j = 0; j < v[i].size(); ++j ) v[i][j].resize(observed.size(), 0); // should be observed.size()-1, but need to compare to old outputs } ci::hmm::xi_full(observed, initial, transition, emission, v); for ( std::size_t i = 0; i < v.size(); ++i ) { for ( std::size_t j = 0; j < v[i].size(); ++j ) { for ( std::size_t k = 0; k < v[i][j].size(); ++k ) std::cout << v[i][j][k] << "\t"; std::cout << std::endl; } std::cout << std::endl; } // for std::cout << "YO NEW-XI" << std::endl; std::vector< std::vector<T> > v2(initial.size()); for ( std::size_t i = 0; i < v2.size(); ++i ) { v2[i].resize(initial.size()); } ci::hmm::details::BackCache< std::vector<T>, std::vector<T>, std::vector< std::vector<T> >, std::vector< std::vector<T> >, T > backcheater(observed, initial, transition, emission); alpha.resize(alpha.size(), 0), beta.resize(beta.size(), 0); foo = backcheater.Next(); // must move up one spot in backward->forward direction for ( std::size_t s = 1; s < observed.size(); ++s ) { std::vector<T> const* foo = backcheater.Next(); ci::hmm::xi(observed, initial, transition, emission, s, *foo, alpha, v2); delete foo; for ( std::size_t i = 0; i < v2.size(); ++i ) { for ( std::size_t j = 0; j < v2[i].size(); ++j ) std::cout << v2[i][j] << "\t"; std::cout << std::endl; } // for } // for std::cout << std::endl; // Problem 3 // Test training std::cout << "Problem 3" << std::endl; std::cout << "Start Initial" << std::endl; for ( std::size_t i = 0; i < initial.size(); ++i ) std::cout << initial[i] << std::endl; std::vector<T> keepobserved(observed), keepinitial(initial); std::vector< std::vector<T> > keeptransition(transition), keepemission(emission); std::size_t numiter = 2; for ( std::size_t i = 0; i < numiter; ++i ) { ci::hmm::train_full(observed, initial, transition, emission); // dolog(initial, transition, emission); std::cout << "Iteration: " << (i+1) << std::endl; std::cout << "New Initial" << std::endl; for ( std::size_t i = 0; i < initial.size(); ++i ) std::cout << initial[i] << std::endl; std::cout << "New Transition" << std::endl; for ( std::size_t i = 0; i < transition.size(); ++i ) { for ( std::size_t j = 0; j < transition[i].size(); ++j ) std::cout << transition[i][j] << "\t"; std::cout << std::endl; } // for std::cout << "New Emission" << std::endl; for ( std::size_t i = 0; i < emission.size(); ++i ) { for ( std::size_t j = 0; j < emission[i].size(); ++j ) { if ( emission[i][j] == ci::inf<T>() ) emission[i][j] = 0; std::cout << emission[i][j] << "\t"; } // for std::cout << std::endl; } // for } // for std::cout << "Finale: *********************" << std::endl; observed = keepobserved; initial = keepinitial; transition = keeptransition; emission = keepemission; std::cout << "New Training" << std::endl; for ( std::size_t i = 0; i < numiter; ++i ) { ci::hmm::train(observed, initial, transition, emission); std::cout << "Iteration " << (i+1) << std::endl; std::cout << "New Initial" << std::endl; std::cout << initial.size() << std::endl; std::cout.flush(); for ( std::size_t i = 0; i < initial.size(); ++i ) std::cout << initial[i] << std::endl; std::cout.flush(); std::cout << "New Transition" << std::endl; for ( std::size_t i = 0; i < transition.size(); ++i ) { for ( std::size_t j = 0; j < transition[i].size(); ++j ) std::cout << transition[i][j] << "\t"; std::cout << std::endl; } // for std::cout << "New Emission" << std::endl; for ( std::size_t i = 0; i < emission.size(); ++i ) { for ( std::size_t j = 0; j < emission[i].size(); ++j ) { if ( emission[i][j] == ci::inf<T>() ) emission[i][j] = 0; std::cout << emission[i][j] << "\t"; } // for std::cout << std::endl; } // for } // for return(0); }
nlopt_result mlsl_minimize(int n, nlopt_func f, void *f_data, const double *lb, const double *ub, /* bounds */ double *x, /* in: initial guess, out: minimizer */ double *minf, nlopt_stopping *stop, nlopt_opt local_opt, int Nsamples, /* #samples/iteration (0=default) */ int lds) /* random or low-discrepancy seq. (lds) */ { nlopt_result ret = NLOPT_SUCCESS; mlsl_data d; int i; pt *p; if (!Nsamples) d.N = 4; /* FIXME: what is good number of samples per iteration? */ else d.N = Nsamples; if (d.N < 1) return NLOPT_INVALID_ARGS; d.n = n; d.lb = lb; d.ub = ub; d.stop = stop; d.f = f; d.f_data = f_data; rb_tree_init(&d.pts, pt_compare); rb_tree_init(&d.lms, lm_compare); d.s = lds ? nlopt_sobol_create((unsigned) n) : NULL; nlopt_set_min_objective(local_opt, fcount, &d); nlopt_set_lower_bounds(local_opt, lb); nlopt_set_upper_bounds(local_opt, ub); nlopt_set_stopval(local_opt, stop->minf_max); d.gamma = MLSL_GAMMA; d.R_prefactor = sqrt(2./K2PI) * pow(gam(n) * MLSL_SIGMA, 1.0/n); for (i = 0; i < n; ++i) d.R_prefactor *= pow(ub[i] - lb[i], 1.0/n); /* MLSL also suggests setting some minimum distance from points to previous local minimiza and to the boundaries; I don't know how to choose this as a fixed number, so I set it proportional to R; see also the comments at top. dlm and dbound are the proportionality constants. */ d.dlm = 1.0; /* min distance/R to local minima (FIXME: good value?) */ d.dbound = 1e-6; /* min distance/R to ub/lb boundaries (good value?) */ p = alloc_pt(n); if (!p) { ret = NLOPT_OUT_OF_MEMORY; goto done; } /* FIXME: how many sobol points to skip, if any? */ nlopt_sobol_skip(d.s, (unsigned) (10*n+d.N), p->x); memcpy(p->x, x, n * sizeof(double)); p->f = f(n, x, NULL, f_data); stop->nevals++; if (!rb_tree_insert(&d.pts, (rb_key) p)) { free(p); ret = NLOPT_OUT_OF_MEMORY; } if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP; else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED; else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED; else if (p->f < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED; while (ret == NLOPT_SUCCESS) { rb_node *node; double R; get_minf(&d, minf, x); /* sampling phase: add random/quasi-random points */ for (i = 0; i < d.N && ret == NLOPT_SUCCESS; ++i) { p = alloc_pt(n); if (!p) { ret = NLOPT_OUT_OF_MEMORY; goto done; } if (d.s) nlopt_sobol_next(d.s, p->x, lb, ub); else { /* use random points instead of LDS */ int j; for (j = 0; j < n; ++j) p->x[j] = nlopt_urand(lb[j],ub[j]); } p->f = f(n, p->x, NULL, f_data); stop->nevals++; if (!rb_tree_insert(&d.pts, (rb_key) p)) { free(p); ret = NLOPT_OUT_OF_MEMORY; } if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP; else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED; else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED; else if (p->f < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED; else { find_closest_pt(n, &d.pts, p); find_closest_lm(n, &d.lms, p); pts_update_newpt(n, &d.pts, p); } } /* distance threshhold parameter R in MLSL */ R = d.R_prefactor * pow(log((double) d.pts.N) / d.pts.N, 1.0 / n); /* local search phase: do local opt. for promising points */ node = rb_tree_min(&d.pts); for (i = (int) (ceil(d.gamma * d.pts.N) + 0.5); node && i > 0 && ret == NLOPT_SUCCESS; --i) { p = (pt *) node->k; if (is_potential_minimizer(&d, p, R, d.dlm*R, d.dbound*R)) { nlopt_result lret; double *lm; double t = nlopt_seconds(); if (nlopt_stop_forced(stop)) { ret = NLOPT_FORCED_STOP; break; } if (nlopt_stop_evals(stop)) { ret = NLOPT_MAXEVAL_REACHED; break; } if (stop->maxtime > 0 && t - stop->start >= stop->maxtime) { ret = NLOPT_MAXTIME_REACHED; break; } lm = (double *) malloc(sizeof(double) * (n+1)); if (!lm) { ret = NLOPT_OUT_OF_MEMORY; goto done; } memcpy(lm+1, p->x, sizeof(double) * n); lret = nlopt_optimize_limited(local_opt, lm+1, lm, stop->maxeval - stop->nevals, stop->maxtime - (t - stop->start)); p->minimized = 1; if (lret < 0) { free(lm); ret = lret; goto done; } if (!rb_tree_insert(&d.lms, lm)) { free(lm); ret = NLOPT_OUT_OF_MEMORY; } else if (nlopt_stop_forced(stop)) ret = NLOPT_FORCED_STOP; else if (*lm < stop->minf_max) ret = NLOPT_MINF_MAX_REACHED; else if (nlopt_stop_evals(stop)) ret = NLOPT_MAXEVAL_REACHED; else if (nlopt_stop_time(stop)) ret = NLOPT_MAXTIME_REACHED; else pts_update_newlm(n, &d.pts, lm); } /* TODO: additional stopping criteria based e.g. on improvement in function values, etc? */ node = rb_tree_succ(node); } } get_minf(&d, minf, x); done: nlopt_sobol_destroy(d.s); rb_tree_destroy_with_keys(&d.lms); rb_tree_destroy_with_keys(&d.pts); return ret; }