CMS 3D CMS Logo

 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
List of all members | Public Member Functions | Private Attributes
hitfit::Chisq_Constrainer Class Reference

Minimize a $\chi^{2}$ subject to a set of constraints. Based on the SQUAW algorithm. More...

#include <Chisq_Constrainer.h>

Inheritance diagram for hitfit::Chisq_Constrainer:
hitfit::Base_Constrainer

Public Member Functions

 Chisq_Constrainer (const Chisq_Constrainer_Args &args)
 
virtual double fit (Constraint_Calculator &constraint_calculator, const Column_Vector &xm, Column_Vector &x, const Column_Vector &ym, Column_Vector &y, const Matrix &G_i, const Diagonal_Matrix &Y, Column_Vector &pullx, Column_Vector &pully, Matrix &Q, Matrix &R, Matrix &S)
 
virtual std::ostream & print (std::ostream &s) const
 Print the state of this instance of Chisq_Constrainer. More...
 
virtual ~Chisq_Constrainer ()
 
- Public Member Functions inherited from hitfit::Base_Constrainer
 Base_Constrainer (const Base_Constrainer_Args &args)
 
virtual ~Base_Constrainer ()
 

Private Attributes

const Chisq_Constrainer_Args _args
 

Additional Inherited Members

- Protected Member Functions inherited from hitfit::Base_Constrainer
bool call_constraint_fcn (Constraint_Calculator &constraint_calculator, const Column_Vector &x, const Column_Vector &y, Row_Vector &F, Matrix &Bx, Matrix &By) const
 Helper function to evaluate constraints. This takes care of checking what the user function returns againts numerical derivatives, it that was requested. More...
 

Detailed Description

Minimize a $\chi^{2}$ subject to a set of constraints. Based on the SQUAW algorithm.

Definition at line 252 of file Chisq_Constrainer.h.

Constructor & Destructor Documentation

hitfit::Chisq_Constrainer::Chisq_Constrainer ( const Chisq_Constrainer_Args args)

Constructor. Create an instance of Chisq_Constrainer from a Chisq_Constrainer_Args object.

Parameters
argsThe parameter settings for this instance.

Definition at line 307 of file Chisq_Constrainer.cc.

315  _args (args)
316 {
317 }
const Base_Constrainer_Args & base_constrainer_args() const
Base_Constrainer(const Base_Constrainer_Args &args)
const Chisq_Constrainer_Args _args
virtual hitfit::Chisq_Constrainer::~Chisq_Constrainer ( )
inlinevirtual

Destructor.

Definition at line 274 of file Chisq_Constrainer.h.

274 {}

Member Function Documentation

double hitfit::Chisq_Constrainer::fit ( Constraint_Calculator constraint_calculator,
const Column_Vector xm,
Column_Vector x,
const Column_Vector ym,
Column_Vector y,
const Matrix G_i,
const Diagonal_Matrix Y,
Column_Vector pullx,
Column_Vector pully,
Matrix Q,
Matrix R,
Matrix S 
)
virtual

@ brief Do a constrained fit. Call the number of well-measured variables Nw, the number of poorly-measured variables Np, and the number of constraints Nc.

Parameters
constraint_calculatorThe object that will be used to evaluate the constraints.
xmMeasured values of the well-measured variables, has dimension Nw.
xBefore the fit: starting value of the well-measured variables for the fit, has dimension Nw. After the fit: final values of the well-measured variables.
ymMeasured values of the poorly-measured variables, has dimension Np.
yBefore the fit: starting value of the poorly-measured variables for the fit, has dimension Np. After the fit: final values of the poorly-measured variables.
G_iError matrix for the well-measured variables, has dimension Nw,Nw.
YInverse error matrix for the poorly-measured variables, has dimension Np,Np.
pullxPull quantities for the well-measured variables, has dimension Nw.
pullyPull quantities for the poorly-measured variables, has dimension Np.
QError matrix for the well-measured variables, has dimension Nw,Nw.
RError matrix for the poorly-measured variables, has dimension Np,Np.
SError matrix for the correlation between well-measured variables and poorly-measured variables, has dimension Nw,Np.
Input:
constraint_calculator, xm, x, ym, y, G_i, y..
Output:
x, y, pullx, pully, Q, R, S.
Return:
$\chi^{2}$ of the fit. Should returns a negative value if the fit does not converge.

cout << "singular matrix!";

Implements hitfit::Base_Constrainer.

Definition at line 320 of file Chisq_Constrainer.cc.

References _args, a, funct::abs(), alpha, assert(), beta, EnergyCorrector::c, alignmentValidation::c1, hitfit::Base_Constrainer::call_constraint_fcn(), hitfit::Chisq_Constrainer_Args::chisq_diff_eps(), hitfit::Chisq_Constrainer_Args::chisq_test_eps(), hitfit::Chisq_Constrainer_Args::constraint_sum_eps(), gather_cfg::cout, hitfit::Chisq_Constrainer_Args::cutsize(), ztail::d, delta, F(), callgraph::G, i, hitfit::Chisq_Constrainer_Args::max_cut(), hitfit::Chisq_Constrainer_Args::maxit(), hitfit::Chisq_Constrainer_Args::min_tot_cutsize(), hitfit::Constraint_Calculator::nconstraints(), hitfit::Chisq_Constrainer_Args::printfit(), class-composition::Q, dttmaxenums::R, hitfit::scalar(), mathSSE::sqrt(), and hitfit::Chisq_Constrainer_Args::use_G().

361 {
362  // Check that the various matrices we've been passed have consistent
363  // dimensionalities.
364  int nvars = x.num_row();
365  assert (nvars == G_i.num_col());
366  assert (nvars == xm.num_row());
367 
368  int nbadvars = y.num_row();
369  assert (nbadvars == Y.num_col());
370  assert (nbadvars == ym.num_row());
371 
372  // If we're going to check the chisq calculation by explicitly using G,
373  // calculate it now from its inverse G_i.
374  Matrix G (nvars, nvars);
375  if (_args.use_G()) {
376  int ierr = 0;
377  G = G_i.inverse (ierr);
378  assert (!ierr);
379  }
380 
381  int nconstraints = constraint_calculator.nconstraints ();
382 
383  // Results of the constraint evaluation function.
384  Row_Vector F (nconstraints); // Constraint vector.
385  Matrix Bx (nvars, nconstraints); // Gradients wrt x
386  Matrix By (nbadvars, nconstraints); // Gradients wrt y
387 
388  // (2) Evaluate the constraints at the starting point.
389  // If the starting point is rejected as invalid,
390  // give up and return an error.
391  if (! call_constraint_fcn (constraint_calculator, x, y, F, Bx, By)) {
392  // cout << "Bad initial values!";
393  // return -1000;
394  return -999.0;
395  }
396 
397  // (3) Initialize variables for the fitting loop.
398  double constraint_sum_last = -1000;
399  double chisq_last = -1000;
400  bool near_convergence = false;
401  double last_step_cutsize = 1;
402 
403  unsigned nit = 0;
404 
405  // Initialize the displacement vectors c and d.
406  Column_Vector c = x - xm;
407  Column_Vector d = y - ym;
408 
409  Matrix E (nvars, nconstraints);
410  Matrix W (nconstraints, nconstraints);
411  Matrix U (nbadvars, nbadvars);
412  Matrix V (nbadvars, nconstraints);
413 
414  // (4) Fitting loop:
415  do {
416  // (5) Calculate E, H, and r.
417  E = G_i * Bx;
418  Matrix H = E.T() * Bx;
419  Row_Vector r = c.T() * Bx + d.T() * By - F;
420 
421  // (6) Solve the linearized system for the new values
422  // of the Lagrange multipliers
423  // $\alpha$ and the new value for the displacements d.
424  Column_Vector alpha (nvars);
425  Column_Vector d1 (nbadvars);
426  if (!solve_linear_system (H, Y, By, r,
427  alpha, d1, W, U, V)) {
429  // return -1000;
430  return -998.0;
431  }
432 
433  // (7) Compute the new values for the displacements c and the chisq.
434  Column_Vector c1 = -E * alpha;
435  double chisq = - scalar (r * alpha);
436 
437  double psi_cut = 0;
438 
439  // (8) Find where this step is going to be taking us.
440  x = c1 + xm;
441  y = d1 + ym;
442 
443  // (9) Set up for cutting this step, should we have to.
444  Matrix save_By = By;
445  Row_Vector save_negF = - F;
446  double this_step_cutsize = 1;
447  double constraint_sum = -1;
448  unsigned ncut = 0;
449 
450  // (10) Evaluate the constraints at the new point.
451  // If the point is rejected, we have to try to cut the step.
452  // We accept the step if:
453  // The constraint sum is below the convergence threshold
454  // constraint_sum_eps, or
455  // This is the first iteration, or
456  // The constraint sum has decreased since the last iteration.
457  // Otherwise, the constraints have gotten worse, and we
458  // try to cut the step.
459  while (! call_constraint_fcn (constraint_calculator, x, y, F, Bx, By) ||
460  ((constraint_sum = norm_infinity (F))
462  nit > 0 &&
463  constraint_sum > constraint_sum_last))
464  {
465 
466  // Doing step cutting...
467  if (nit > 0 && _args.printfit() && ncut == 0) {
468  cout << "(" << chisq << " " << chisq_last << ") ";
469  }
470 
471  // (10a) If this is the first time we've tried to cut this step,
472  // test to see if the chisq is stationary. If it hasn't changed
473  // since the last iteration, try a directed step.
474  if (ncut == 0 &&
475  abs (chisq - chisq_last) < _args.chisq_diff_eps()) {
476 
477  // Trying a directed step now.
478  // Try to make the smallest step which satisfies the
479  // (linearized) constraints.
480  if (_args.printfit())
481  cout << " directed step ";
482 
483  // (10a.i) Solve the linearized system for $\beta$ and
484  // the y-displacement vector $\delta$.
485  Column_Vector beta (nconstraints);
486  Column_Vector delta (nbadvars);
487  solve_linear_system (H, Y, save_By, save_negF,
488  beta, delta, W, U, V);
489 
490  // (10a.ii) Get the x-displacement vector $\gamma$.
491  Column_Vector gamma = -E * beta;
492 
493  // (10a.iii) Find the destination of the directed step.
494  x = c + xm + gamma;
495  y = d + ym + delta;
496 
497  // (10a.iv) Accept this point if it's not rejected by the constraint
498  // function, and the constraints improve.
499  if (call_constraint_fcn (constraint_calculator, x, y, F, Bx, By) &&
500  (constraint_sum = norm_infinity (F)) > 0 &&
501  (constraint_sum < constraint_sum_last)) {
502 
503  // Accept this step. Calculate the chisq and new displacement
504  // vectors.
505  chisq = chisq_last - scalar ((-save_negF + r*2) * beta);
506  c1 = x - xm;
507  d1 = y - ym;
508 
509  // Exit from step cutting loop.
510  break;
511  }
512  }
513 
514  // If this is the first time we're cutting the step,
515  // initialize $\psi$.
516  if (ncut == 0)
517  psi_cut = scalar ((save_negF - r) * alpha);
518 
519  // (10b) Give up if we've tried to cut this step too many times.
520  if (++ncut > _args.max_cut()) {
521  // cout << " Too many cut steps ";
522  // return -1000;
523  return -997.0;
524  }
525 
526  // (10c) Set up the size by which we're going to cut this step.
527  // Normally, this is cutsize. But if this is the first time we're
528  // cutting this step and the last step was also cut, set the cut
529  // size to twice the final cut size from the last step (provided
530  // that it is less than cutsize).
531  double this_cutsize = _args.cutsize();
532  if (ncut == 1 && last_step_cutsize < 1) {
533  this_cutsize = 2 * last_step_cutsize;
534  if (this_cutsize > _args.cutsize())
535  this_cutsize = _args.cutsize();
536  }
537 
538  // (10d) Keep track of the total amount by which we've cut this step.
539  this_step_cutsize *= this_cutsize;
540 
541  // If it falls below min_tot_cutsize, give up.
542  if (this_step_cutsize < _args.min_tot_cutsize()) {
543  // cout << "Cut size underflow ";
544  // return -1000;
545  return -996.0;
546  }
547 
548  // (10e) Cut the step: calculate the new displacement vectors.
549  double cutleft = 1 - this_cutsize;
550  c1 = c1 * this_cutsize + c * cutleft;
551  d1 = d1 * this_cutsize + d * cutleft;
552 
553  // (10f) Calculate the new chisq.
554  if (chisq_last >= 0) {
555  chisq = this_cutsize*this_cutsize * chisq +
556  cutleft*cutleft * chisq_last +
557  2*this_cutsize*cutleft * psi_cut;
558  psi_cut = this_cutsize * psi_cut + cutleft * chisq_last;
559  }
560  else
561  chisq = chisq_last;
562 
563  // Log what we've done.
564  if (_args.printfit()) {
565  cout << constraint_sum << " cut " << ncut << " size "
566  << setiosflags (ios_base::scientific)
567  << this_cutsize << " tot size " << this_step_cutsize
568  << resetiosflags (ios_base::scientific)
569  << " " << chisq << "\n";
570  }
571 
572  // Find the new step destination.
573  x = c1 + xm;
574  y = d1 + ym;
575 
576  // Now, go and test the step again for acceptability.
577  }
578 
579  // (11) At this point, we have an acceptable step.
580  // Shuffle things around to prepare for the next step.
581  last_step_cutsize = this_step_cutsize;
582 
583  // If requested, calculate the chisq using G to test for
584  // possible loss of precision.
585  double chisq_b = 0;
586  if (_args.use_G()) {
587  chisq_b = scalar (c1.T() * G * c1) + scalar (d1.T() * Y * d1);
588  if (chisq >= 0 &&
589  abs ((chisq - chisq_b) / chisq) > _args.chisq_test_eps()) {
590  cout << chisq << " " << chisq_b
591  << "lost precision?\n";
592  abort ();
593  }
594  }
595 
596  // Log what we're doing.
597  if (_args.printfit()) {
598  cout << chisq << " ";
599  if (_args.use_G())
600  cout << chisq_b << " ";
601  }
602 
603  double z2 = abs (chisq - chisq_last);
604 
605  if (_args.printfit()) {
606  cout << constraint_sum << " " << z2 << "\n";
607  }
608 
609  c = c1;
610  d = d1;
611  chisq_last = chisq;
612  constraint_sum_last = constraint_sum;
613 
614  // (12) Test for convergence. The conditions must be satisfied
615  // for two iterations in a row.
616  if (chisq >= 0 && constraint_sum < _args.constraint_sum_eps() &&
617  z2 < _args.chisq_diff_eps())
618  {
619  if (near_convergence) break; // Converged! Exit loop.
620  near_convergence = true;
621  }
622  else
623  near_convergence = false;
624 
625  // (13) Give up if we've done this too many times.
626  if (++nit > _args.maxit()) {
627  // cout << "too many iterations";
628  // return -1000;
629  return -995.0;
630  }
631 
632  } while (1);
633 
634  // (15) Ok, we have a successful fit!
635 
636 
637  // Calculate the error matrices.
638  Q = E * W * E.T();
639  S = - E * V.T();
640  R = U;
641 
642  // And the vectors of pull functions.
643  pullx = Column_Vector (nvars);
644  for (int i=1; i<=nvars; i++) {
645  double a = Q(i,i);
646  if (a < 0)
647  pullx(i) = c(i) / sqrt (-a);
648  else {
649  pullx(i) = 0;
650  // cout << " bad pull fcn for var " << i << " (" << a << ") ";
651  }
652  }
653 
654  pully = Column_Vector (nbadvars);
655  for (int i=1; i<=nbadvars; i++) {
656  double a = 1 - Y(i,i)*R(i,i);
657  if (a > 0)
658  pully(i) = d(i) * sqrt (Y(i,i) / a);
659  else {
660  pully(i) = 0;
661  // cout << " bad pull fcn for badvar " << i << " ";
662  }
663  }
664 
665  // Finish calculation of Q.
666  Q = Q + G_i;
667 
668  // Return the final chisq.
669  return chisq_last;
670 }
const double beta
dbl * delta
Definition: mlp_gen.cc:36
int i
Definition: DBlmapReader.cc:9
float alpha
Definition: AMPTWrapper.h:95
assert(m_qm.get())
CLHEP::HepVector Column_Vector
Definition: matutil.h:66
CLHEP::HepMatrix Matrix
Definition: matutil.h:65
tuple d
Definition: ztail.py:151
T sqrt(T t)
Definition: SSEVec.h:48
Abs< T >::type abs(const T &t)
Definition: Abs.h:22
bool call_constraint_fcn(Constraint_Calculator &constraint_calculator, const Column_Vector &x, const Column_Vector &y, Row_Vector &F, Matrix &Bx, Matrix &By) const
Helper function to evaluate constraints. This takes care of checking what the user function returns a...
tuple G
Definition: callgraph.py:12
double S(const TLorentzVector &, const TLorentzVector &)
Definition: Particle.cc:99
double a
Definition: hdecay.h:121
const Chisq_Constrainer_Args _args
tuple cout
Definition: gather_cfg.py:121
Definition: DDAxes.h:10
static uInt32 F(BLOWFISH_CTX *ctx, uInt32 x)
Definition: blowfish.cc:281
Row-vector class. CLHEP doesn&#39;t have a row-vector class, so HitFit uses its own. This is only a simpl...
Definition: matutil.h:83
double scalar(const CLHEP::HepGenMatrix &m)
Return the matrix as a scalar. Raise an assertion if the matris is not .
Definition: matutil.cc:183
std::ostream & hitfit::Chisq_Constrainer::print ( std::ostream &  s) const
virtual

Print the state of this instance of Chisq_Constrainer.

Parameters
sThe output stream to which the output is sent.

Reimplemented from hitfit::Base_Constrainer.

Definition at line 673 of file Chisq_Constrainer.cc.

References hitfit::Base_Constrainer::print(), and alignCSCRings::s.

683 {
685  s << " printfit: " << _args.printfit()
686  << " use_G: " << _args.use_G() << "\n";
687  s << " constraint_sum_eps: " << _args.constraint_sum_eps()
688  << " chisq_diff_eps: " << _args.chisq_diff_eps()
689  << " chisq_test_eps: " << _args.chisq_test_eps() << "\n";
690  s << " maxit: " << _args.maxit()
691  << " max_cut: " << _args.max_cut()
692  << " min_tot_cutsize: " << _args.min_tot_cutsize()
693  << " cutsize: " << _args.cutsize() << "\n";
694  return s;
695 }
const Chisq_Constrainer_Args _args
virtual std::ostream & print(std::ostream &s) const
Print out internal state to output stream.

Member Data Documentation

const Chisq_Constrainer_Args hitfit::Chisq_Constrainer::_args
private

Parameter settings for this instance of Chisq_Constrainer.

Definition at line 376 of file Chisq_Constrainer.h.

Referenced by Vispa.Main.Application.Application::_readCommandLineAttributes(), and fit().