Unexpected Output from Minuit2

Hello everyone,

I am having some issues understanding the output of a chi squared minimization that I am performing with Minuit2. I have the stand alone version of Minuit2 6.15.

Below is my code. What I wanted to do was to have the mass(int i, double p0, double p1, double p2, double p3){} provide the relevant eigenvalues to be used in the chi squared minimization. It should be in total seven eigenvalues. But when I echo print the output of mass() to the screen it actually keeps printing numbers.

#include "Minuit2/FunctionMinimum.h"
#include "Minuit2/MnUserParameterState.h"
#include "Minuit2/MnPrint.h"
#include "Minuit2/MnMigrad.h"
#include "Minuit2/FCNBase.h"

#include <iostream>
#include <iomanip>
#include <string>
#include <vector>
#include <cmath>
#include <Eigen/Dense>

using namespace ROOT::Minuit2;
using namespace Eigen;

const double PI = 4*atan(1);
// Define minimizer class (inherits from FCNBase)
class Minimizer : public FCNBase {

private:

  const std::vector< std::vector<double> > &m_data;
  //  const std::vector<double> &m_mass;

public:

  Minimizer(const std::vector< std::vector<double> > &data) : m_data(data) {}

  ~Minimizer() {}
  // functions to find factorial and double factorial of given number - used in the Vqq matrix element
 //Omitted here (but they are in the actual code)

  double diagonalization(double n, double L, double p0, double p1, double p2, double p3){
    // Declare the number of terms in the expansion and the number of iterations for the numerical integrals
    int N1 = 12;

    // Declare the variational parameters - values taken from the hybrid decay paper: https://arxiv.org/abs/2005.10850
    double alphaInit = 0.005;
    // Define the matrices - the dimension can be set to be any of the above indexes since they are generally the same
    MatrixXd HMX(N1, N1);
    MatrixXd NMX(N1, N1);
    MatrixXd KMX(N1, N1);
    MatrixXd VMX(N1, N1);

    //Declare the variables for the minimum eigenvalue
    double minEvalue0 = 0.0; // ground state eigenvalue
    double minEvalue1 = 0.0; // first excited state eigenvalue
    double minEvalue2 = 0.0; // second excited state eigenvalue
    double minEvalue3 = 0.0; // third excited state eigenvalue

    std::vector<double> eValues0;
    std::vector<double> eValues1;
    std::vector<double> eValues2;
    std::vector<double> eValues3;
    std::vector<double> minEvalues;

    // Loop over the variational parameters and the matrix elements (k1=n', l1=m', k2=n, l2=m).
    for (double alpha = alphaInit; alpha <= 1.000; alpha += 0.005){
      for (int k1 = 1; k1 <= N1; k1++){
        for (int k2 = 1; k2 <= N1; k2++){
          // Define the full Hamiltonian in configuration space - works for all values of L
          // Overlap Matrix
          NMX(k1-1,k2-1) = pow(2.0,L + 1)*sqrt(2.0)*pow(k1*k2,0.75 + L/2.0)/(pow(k1+k2,1.5 + L));
          // Mass and kinetic terms
          KMX(k1-1,k2-1) = (pow(2.0,L + 1)*sqrt(2.0)*pow(k1*k2,0.75 + L/2.0)/(pow(k1+k2,1.5 + L))) * (2.0*p0 + (3.0+2.0*L)*(k1*k2)*alpha*alpha/(p0*(k1+k2)));
          // Potential term
          VMX(k1-1,k2-1) = (powerfactorial(L)*pow(k1*k2,0.75 + L/2.0)/(doublefactorial(2*L+1)*sqrt(PI)*alpha*pow(k1+k2,2.0+L)))*(2*p1*alpha*alpha*(k1+k2)-3*(L+1)*p2);
        }
      }
      // Diagonalize and print the eigenvalues
      HMX = KMX - (4.0/3.0)*VMX;

      std::setprecision(8);
      GeneralizedSelfAdjointEigenSolver<MatrixXd> es(HMX,NMX);
      //pushback eigenvalues into vectors
      eValues0.push_back(es.eigenvalues()[0]);
      eValues1.push_back(es.eigenvalues()[1]);
      eValues2.push_back(es.eigenvalues()[2]);
      eValues3.push_back(es.eigenvalues()[3]);

    }
    // Calculate the minimum eigenvalue and the corresponding parameters
    minEvalue0 = eValues0[0];
    minEvalue1 = eValues1[0];
    minEvalue2 = eValues2[0];
    minEvalue3 = eValues3[0];

    //cout << "\n";
    //cout << "Here is the full list of eigenvalues: " << std::endl;

    for(unsigned int i = 0; i < eValues0.size(); i++){
      if (eValues0[i] < minEvalue0){
        minEvalue0 = eValues0[i];
      }
    }
    for(unsigned int i = 0; i < eValues1.size(); i++){
      if (eValues1[i] < minEvalue1){
        minEvalue1 = eValues1[i];
      }
    }

    for(unsigned int i = 0; i < eValues2.size(); i++){
      if (eValues2[i] < minEvalue2){
        minEvalue2 = eValues2[i];
      }
    }

    for(unsigned int i = 0; i < eValues3.size(); i++){
      if (eValues3[i] < minEvalue3){
        minEvalue3 = eValues3[i];
      }
    }
    //push_back all the minimized eigenvalues into a vector
    minEvalues.push_back(minEvalue0);
    minEvalues.push_back(minEvalue1);
    minEvalues.push_back(minEvalue2);
    minEvalues.push_back(minEvalue3);

    double eigenvalue = minEvalues[n-1]-p3;//return the desired eigenvalue from minEvalues
    return eigenvalue;
  }

  // Define function that selects the state for diagonalization(n, L, p0, p1, p2, p3)
  double mass (int state, double p0, double p1, double p2, double p3){
    double n;
    double L;
    double mesonMass = 0.0;

    if (state == 0){
      n = 1.0;
      L = 0.0;
  ...
    else if (state == 6){
      n = 4.0;
      L = 2.0;
    }
    mesonMass = diagonalization(n, L, p0, p1, p2, p3);
    return mesonMass;
  }

  double operator() (const std::vector<double> &params) const {
    double X2 = 0.0;
    //std::cout << mass(0,params[0], params[1], params[2], params[3]) << std::endl;
    //std::vector<double> mass;
    for (int i=0; i<m_data[0].size(); i++) {
      double n = m_data[0][i];
      double L = m_data[1][i];
      double f = mass(i, params[0], params[1], params[2], params[3]);
      X2 += (m_data[2][i] - f)*(m_data[2][i] - f)/(m_data[2][i]);
      std::cout << "data[2][i] = " << m_data[2][i] << std::endl;
      std::cout << "mass[i]" << f << std::endl;
    }
    return X2;
  }
  //set to 1 for chi-sq and 0.5 for log-likelihood
  double Up() const {return 1.0;}
};

int main(){

  std::vector< std::vector<double> > data(3);
  // (1S)
  data[0].push_back(1.0);
  data[1].push_back(0.0);
  data[2].push_back(3.0687);
  // (2S)
  data[0].push_back(2.0);
  data[1].push_back(0.0);
  data[2].push_back(3.6740);
  // (1P)
  data[0].push_back(2.0);
  data[1].push_back(1.0);
  data[2].push_back(3.5259);
  // (1D)
  data[0].push_back(3.0);
  data[1].push_back(2.0);
  data[2].push_back(3.8282);//data[2].push_back(3.7737);
  // (3S)
  data[0].push_back(3.0);
  data[1].push_back(0.0);
  data[2].push_back(4.0390);//4.040);
  // (4S)
  data[0].push_back(4.0);
  data[1].push_back(0.0);
  data[2].push_back(4.4214);
  // (2D)
  data[0].push_back(4.0);
  data[1].push_back(2.0);
  data[2].push_back(4.1915);

  std::vector<double> params(4,1.0);
  std::vector<double> err(4,0.1);
  params[0] = 1.60; //mc
  params[1] = 0.50;  //alphaS
  params[2] = 0.14; //b
  params[3] = 0.25; //mass shift
  std::cout << "Initial values of parameters: " << std::endl;
  for (int i = 0; i < 4; i++){
    std::cout << "params[" << i << "] = " << params[i] << std::endl;
  }
  std::cout << "Computing the values of the parameters..." << std::endl;

  //minimize
  Minimizer fcn(data);
  Minimizer example(data);
  for(int i=0; i<7; i++){
    std::cout << example.mass(i,params[0],params[1],params[2],params[3]) << std::endl;
  }
    //std::cout << "data[0].size " << data[0].size() << std::endl;
  MnMigrad migrad(fcn, params, err);
  FunctionMinimum minParams = migrad();
  std::cout << " chi^2 = " << minParams.Fval() << std::endl;
  std::cout << " for the following values:\n " << "mass c: " << minParams.UserState().Value(0) << ", alphaS: " << minParams.UserState().Value(1) << ", b: " \
            << minParams.UserState().Value(2) << ", shift: " << minParams.UserState().Value(3) << std::endl;

  std::cout << "Process completed." << std::endl;
  return 0;
}

When I print the result of example.mass() I get exactly the seven values that I expected.

3.06935
3.6354
3.9012
4.41176
4.0215
4.34403
4.68653

But std::cout << "mass[i] " << f << std::endl;
makes no sense at all to me, as it keeps printing eigenvalues:

mass[i]2.86003
mass[i]3.41612
mass[i]3.67878
mass[i]4.19538
mass[i]3.80451
mass[i]4.13111
mass[i]4.47528
mass[i]2.86004
mass[i]3.41613
mass[i]3.67879
mass[i]4.19539
mass[i]3.80452
mass[i]4.13112
mass[i]4.47528
...
mass[i]3.13612
mass[i]3.52386
mass[i]3.70813
mass[i]4.0931
mass[i]3.80947
mass[i]4.05334
mass[i]4.30513

etc. What I really don’t understand is why it keeps printing if data[0].size() is 7. Am I missing something about Minuit2 here is is it just my mistake in the way I wrote the code? You can see from my code that I am a Newbie, so any help would be appreciated.

Thank you in advance.

Christian


ROOT Version:
Platform: Linux
Compiler: gcc


I think @moneta can help you.

Thank you. I would greatly appreciate it if @Wile_E_Coyote or @moneta or @henryiii or any other expert would help me with this.

Thank you.