8 #ifndef IMPISD_UNIVARIATE_FUNCTIONS_H
9 #define IMPISD_UNIVARIATE_FUNCTIONS_H
11 #include <IMP/isd/isd_config.h>
17 #include <Eigen/Dense>
19 #define IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM 1e-7
21 IMPISD_BEGIN_NAMESPACE
35 virtual Eigen::VectorXd operator() (
40 bool stupid)
const = 0;
43 virtual bool has_changed()
const = 0;
46 virtual void update() = 0;
52 virtual void add_to_derivatives(
const Floats& x,
60 virtual void add_to_particle_derivative(
unsigned particle_no,
69 virtual Eigen::VectorXd get_derivative_vector(
70 unsigned particle_no,
const FloatsList& xlist)
const = 0;
75 bool stupid)
const = 0;
78 virtual Eigen::VectorXd get_second_derivative_vector(
79 unsigned particle_a,
unsigned particle_b,
83 virtual FloatsList get_second_derivative_vector(
84 unsigned particle_a,
unsigned particle_b,
85 const FloatsList& xlist,
bool stupid)
const = 0;
88 virtual unsigned get_ndims_x()
const = 0;
91 virtual unsigned get_ndims_y()
const = 0;
94 virtual unsigned get_number_of_particles()
const = 0;
97 virtual bool get_particle_is_optimized(
unsigned particle_no)
const = 0;
100 virtual unsigned get_number_of_optimized_particles()
const = 0;
118 IMP_LOG_TERSE(
"Linear1DFunction: constructor" << std::endl);
121 a_val_ =
Nuisance(a).get_nuisance();
122 b_val_ =
Nuisance(b).get_nuisance();
126 double tmpa =
Nuisance(a_).get_nuisance();
127 double tmpb =
Nuisance(b_).get_nuisance();
128 if ((std::abs(tmpa - a_val_) >
129 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
130 || (std::abs(tmpb - b_val_) >
131 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM))
142 a_val_ =
Nuisance(a_).get_nuisance();
143 b_val_ =
Nuisance(b_).get_nuisance();
145 << a_val_ <<
" b:=" << b_val_ << std::endl);
150 Floats ret(1,a_val_*x[0]+b_val_);
156 unsigned M = xlist.size();
157 Eigen::VectorXd retlist(M);
158 for (
unsigned i = 0; i < M; i++)
161 "expecting a 1-D vector");
162 retlist(i) = a_val_*xlist[i][0]+b_val_;
169 Eigen::VectorXd vec((*
this)(xlist));
171 for (
unsigned i=0; i<xlist.size(); i++)
172 ret.push_back(
Floats(1,vec(i)));
180 Nuisance(a_).add_to_nuisance_derivative(x[0], accum);
182 Nuisance(b_).add_to_nuisance_derivative(1, accum);
191 Nuisance(a_).add_to_nuisance_derivative(value, accum);
194 Nuisance(b_).add_to_nuisance_derivative(value, accum);
197 IMP_THROW(
"Invalid particle number", ModelException);
202 unsigned particle_no,
const FloatsList& xlist)
const
204 unsigned N=xlist.size();
205 Eigen::VectorXd ret(N);
209 for (
unsigned i=0; i<N; i++)
210 ret(i) = xlist[i][0];
216 IMP_THROW(
"Invalid particle number", ModelException);
224 Eigen::MatrixXd mat(xlist.size(),2);
228 for (
int i=0; i<mat.rows(); i++)
231 for (
int j=0; j<mat.cols(); j++)
232 line.push_back(mat(i,j));
239 unsigned,
unsigned,
const FloatsList& xlist)
const
242 unsigned N=xlist.size();
243 Eigen::VectorXd H(Eigen::VectorXd::Zero(N));
248 unsigned particle_a,
unsigned particle_b,
252 particle_a, particle_b, xlist));
254 for (
int i=0; i<mat.rows(); i++)
257 for (
int j=0; j<mat.cols(); j++)
258 line.push_back(mat(i,j));
274 return Nuisance(a_).get_nuisance_is_optimized();
276 return Nuisance(b_).get_nuisance_is_optimized();
278 IMP_THROW(
"Invalid particle number", ModelException);
285 if (
Nuisance(a_).get_nuisance_is_optimized()) count++;
286 if (
Nuisance(b_).get_nuisance_is_optimized()) count++;
305 <<
" * x + " << b_val_ << std::endl, {});
308 Pointer<Particle> a_,b_;
309 double a_val_, b_val_;
330 G_(G), Rg_(Rg), d_(d), s_(s), A_(A)
332 IMP_LOG_TERSE(
"GeneralizedGuinierPorodFunction: constructor"
343 double tmpG =
Scale(G_).get_scale();
344 double tmpRg =
Scale(Rg_).get_scale();
345 double tmpd =
Scale(d_).get_scale();
346 double tmps =
Scale(s_).get_scale();
347 double tmpA =
Nuisance(A_).get_nuisance();
348 if ((std::abs(tmpG - G_val_) > IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
349 || (std::abs(tmpRg - Rg_val_) >
350 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
351 || (std::abs(tmpd - d_val_) >
352 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
353 || (std::abs(tmps - s_val_) >
354 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM)
355 || (std::abs(tmpA - A_val_) >
356 IMP_ISD_UNIVARIATE_FUNCTIONS_MINIMUM))
359 "GeneralizedGuinierPorodFunction: has_changed():");
368 G_val_ =
Scale(G_).get_scale();
369 Rg_val_ =
Scale(Rg_).get_scale();
370 d_val_ =
Scale(d_).get_scale();
371 s_val_ =
Scale(s_).get_scale();
372 A_val_ =
Nuisance(A_).get_nuisance();
373 q1_param_ = std::sqrt((d_val_-s_val_)*(3-s_val_)/2.);
374 D_param_ = G_val_ *std::exp(-IMP::square(q1_param_)/(3-s_val_));
375 q1_param_ = q1_param_ / Rg_val_;
376 D_param_ *= std::pow(q1_param_,d_val_-s_val_);
377 IMP_LOG_TERSE(
"GeneralizedGuinierPorodFunction: update() G:= "
379 <<
" Rg:=" << Rg_val_
383 <<
" Q1.Rg =" << q1_param_*Rg_val_
384 <<
" D =" << D_param_
399 Floats ret(1,get_value(x[0]));
405 unsigned M=xlist.size();
406 Eigen::VectorXd retlist(M);
407 for (
unsigned i = 0; i < M; i++)
410 "expecting a 1-D vector");
411 retlist(i) = get_value(xlist[i][0]);
418 Eigen::VectorXd vec((*
this)(xlist));
420 for (
unsigned i=0; i<xlist.size(); i++)
421 ret.push_back(
Floats(1,vec(i)));
429 double value = get_value(qval) - A_val_;
432 deriv = value/G_val_;
434 "derivative for G is nan.");
435 Scale(G_).add_to_nuisance_derivative(deriv, accum);
436 if (qval <= q1_param_)
439 deriv = - value * 2*IMP::square(qval)*Rg_val_/(3-s_val_);
441 "derivative for Rg is nan.");
442 Scale(Rg_).add_to_nuisance_derivative(deriv, accum);
447 * (IMP::square((qval*Rg_val_)/(3-s_val_)) + std::log(qval));
449 "derivative for s is nan.");
450 Scale(s_).add_to_nuisance_derivative(deriv, accum);
453 deriv = value * (s_val_-d_val_)/Rg_val_;
455 "derivative for Rg is nan.");
456 Scale(Rg_).add_to_nuisance_derivative(deriv, accum);
458 deriv = value * std::log(q1_param_/qval);
460 "derivative for d is nan.");
461 Scale(d_).add_to_nuisance_derivative(deriv, accum);
463 deriv = - value * ( (d_val_-s_val_)/(2*(3-s_val_))
464 + std::log(q1_param_) );
466 "derivative for d is nan.");
467 Scale(s_).add_to_nuisance_derivative(deriv, accum);
471 Nuisance(A_).add_to_nuisance_derivative(deriv, accum);
481 "derivative for G is nan.");
482 Scale(G_).add_to_scale_derivative(value, accum);
486 "derivative for Rg is nan.");
487 Scale(Rg_).add_to_scale_derivative(value, accum);
491 "derivative for d is nan.");
492 Scale(d_).add_to_scale_derivative(value, accum);
496 "derivative for s is nan.");
497 Scale(s_).add_to_scale_derivative(value, accum);
501 "derivative for A is nan.");
502 Nuisance(A_).add_to_nuisance_derivative(value, accum);
505 IMP_THROW(
"Invalid particle number", ModelException);
510 unsigned particle_no,
const FloatsList& xlist)
const
512 unsigned N=xlist.size();
513 Eigen::VectorXd ret(N);
518 ret = ((*this)(xlist)
519 -Eigen::VectorXd::Constant(N,A_val_))/G_val_;
522 for (
unsigned i=0; i<N; i++)
524 double qval = xlist[i][0];
525 if (qval <= q1_param_)
528 ret(i) = - (get_value(qval) - A_val_)
529 * 2*IMP::square(qval)*Rg_val_/(3-s_val_);
532 ret(i) = (get_value(qval)-A_val_)
533 * (s_val_-d_val_)/Rg_val_;
538 for (
unsigned i=0; i<N; i++)
540 double qval = xlist[i][0];
541 if (qval <= q1_param_)
547 ret(i) = (get_value(qval)-A_val_)
548 * std::log(q1_param_/qval);
553 for (
unsigned i=0; i<N; i++)
555 double qval = xlist[i][0];
556 if (qval <= q1_param_)
560 ret(i) = - (get_value(qval) - A_val_)
561 * (IMP::square((qval*Rg_val_)
566 ret(i) = - (get_value(qval) - A_val_)
567 * ( (d_val_-s_val_)/(2*(3-s_val_))
568 + std::log(q1_param_) );
573 ret = Eigen::VectorXd::Constant(N,1);
576 IMP_THROW(
"Invalid particle number", ModelException);
584 Eigen::MatrixXd mat(xlist.size(),5);
591 for (
int i=0; i<mat.rows(); i++)
594 for (
int j=0; j<mat.cols(); j++)
595 line.push_back(mat(i,j));
602 unsigned particle_a,
unsigned particle_b,
606 IMP_THROW(
"Invalid particle 1 number", ModelException);
608 IMP_THROW(
"Invalid particle 2 number", ModelException);
609 unsigned N=xlist.size();
611 if (particle_a == 4 || particle_b == 4)
612 return Eigen::VectorXd::Zero(N);
613 unsigned pa = std::min(particle_a,particle_b);
614 unsigned pb = std::max(particle_a,particle_b);
615 Eigen::VectorXd ret(N);
623 ret.noalias() = Eigen::VectorXd::Zero(N);
655 for (
unsigned i=0; i<N; i++)
657 double qval = xlist[i][0];
658 if (qval <= q1_param_)
663 ret(i) = (get_value(qval) - A_val_)
664 * 2*IMP::square(qval)/(3-s_val_)
665 * (2*IMP::square(qval*Rg_val_)/(3-s_val_) -1);
668 ret(i) = (get_value(qval) - A_val_)
669 * (d_val_-s_val_)/IMP::square(Rg_val_)
676 for (
unsigned i=0; i<N; i++)
678 double qval = xlist[i][0];
679 if (qval <= q1_param_)
686 double val=(get_value(qval)-A_val_);
687 ret(i) = -val/Rg_val_
688 - (val*std::log(q1_param_/qval)
689 * (d_val_-s_val_)/Rg_val_);
695 for (
unsigned i=0; i<N; i++)
697 double qval = xlist[i][0];
698 double val=(get_value(qval)-A_val_);
699 if (qval <= q1_param_)
704 * (IMP::square((qval*Rg_val_)
708 -2*IMP::square(qval)*Rg_val_/(3-s_val_)
709 *(deriv + val/(3-s_val_));
714 * ( (d_val_-s_val_)/(2*(3-s_val_))
715 + std::log(q1_param_) );
716 ret(i) = (val - (d_val_-s_val_)*deriv)
733 for (
unsigned i=0; i<N; i++)
735 double qval = xlist[i][0];
736 if (qval <= q1_param_)
743 double val=(get_value(qval)-A_val_);
745 IMP::square(std::log(q1_param_/qval))
746 +1/(2*(d_val_-s_val_)));
753 double lterm=(d_val_-s_val_)/(2*(3-s_val_))
754 + std::log(q1_param_);
755 double rterm=0.5*(1/(3-s_val_) + 1/(d_val_-s_val_));
756 for (
unsigned i=0; i<N; i++)
758 double qval = xlist[i][0];
759 if (qval <= q1_param_)
767 double val=(get_value(qval)-A_val_);
769 std::log(q1_param_/qval)*lterm + rterm);
788 IMP::square( 0.5*(d_val_-s_val_)/(3-s_val_)
789 + std::log(q1_param_) )
790 + 0.5*((6 - s_val_ - d_val_)/IMP::square(3-s_val_)
791 + 1./(d_val_-s_val_));
792 for (
unsigned i=0; i<N; i++)
794 double qval = xlist[i][0];
795 double val=(get_value(qval)-A_val_);
796 if (qval <= q1_param_)
802 IMP::square((qval*Rg_val_)/(3-s_val_));
804 (IMP::square(factor + std::log(qval))
805 - 2*factor/(3-s_val_));
811 ret(i) = val * cterm;
833 unsigned particle_a,
unsigned particle_b,
837 particle_a, particle_b, xlist));
839 for (
int i=0; i<mat.rows(); i++)
842 for (
int j=0; j<mat.cols(); j++)
843 line.push_back(mat(i,j));
859 return Scale(G_).get_scale_is_optimized();
861 return Scale(Rg_).get_scale_is_optimized();
863 return Scale(d_).get_scale_is_optimized();
865 return Scale(s_).get_scale_is_optimized();
867 return Nuisance(A_).get_nuisance_is_optimized();
869 IMP_THROW(
"Invalid particle number", ModelException);
876 if (
Scale(G_).get_scale_is_optimized()) count++;
877 if (
Scale(Rg_).get_scale_is_optimized()) count++;
878 if (
Scale(d_).get_scale_is_optimized()) count++;
879 if (
Scale(s_).get_scale_is_optimized()) count++;
880 if (
Nuisance(A_).get_nuisance_is_optimized()) count++;
903 <<
" Rg = " << Rg_val_
907 <<
" Q1.Rg = " << q1_param_*Rg_val_
912 inline double get_value(
double q)
const
917 value = A_val_ + G_val_/std::pow(q,s_val_)
918 * std::exp(- IMP::square(q*Rg_val_)/(3-s_val_));
920 value = A_val_ + D_param_/std::pow(q,d_val_);
925 Pointer<Particle> G_,Rg_,d_,s_,A_;
926 double G_val_,Rg_val_,d_val_,s_val_,A_val_,q1_param_,D_param_;