scikit-hep/iminuit

Minuit object has an error when serialized with Pickle

Closed this issue · 1 comments

I've tried saving the Minuit object via pickle, but find that has an error when I try to print the object after loading it:

See the script below that generated this error

Traceback (most recent call last):
  File "testiminuit-pickle.py", line 88, in <module>
    print(pMinuit)
  File "/u/ec/roodman/.local/lib/python3.8/site-packages/iminuit/minuit.py", line 1972, in __str__
    s.append(str(self.covariance))
  File "/u/ec/roodman/.local/lib/python3.8/site-packages/iminuit/util.py", line 332, in __str__
    return _repr_text.matrix(self)
  File "/u/ec/roodman/.local/lib/python3.8/site-packages/iminuit/_repr_text.py", line 178, in matrix
    names = tuple(arr._var2pos)
TypeError: 'NoneType' object is not iterable

import numpy as np
import pickle
from iminuit import Minuit

class testing(object):

    def __init__(self):
        self.x = np.arange(0.,100.,1.)
        self.yerr = np.random.normal(size=100)

    def yfunc(self,par):
        y = par[0] + par[1]*self.x + par[2]*self.x**2
        return y

    def mkdata(self):
        truepar = np.array([4.0,-0.4,2.0])
        self.ydata = self.yfunc(truepar) + 1.*self.yerr

    def chisq(self,par):

        # calculate chi2
        dy = self.ydata-self.yfunc(par)
        chisquared = np.sum(dy**2)
        print("chisq = ",chisquared)
        return chisquared

    def calcgrad(self,par):

        gradArr = np.zeros(par.shape[0])
        gradArr[0] = -2. * np.sum( (self.ydata-self.yfunc(par)) )
        gradArr[1] = -2. * np.sum( (self.ydata-self.yfunc(par)) * self.x )
        gradArr[2] = -2. * np.sum( (self.ydata-self.yfunc(par)) * self.x**2 )
        return gradArr


#chisq.errordef = Minuit.LEAST_SQUARES

startpar = [3.,0.,1.]
names = ["a","b","c"]

atest = testing()
atest.mkdata()

gMinuit = Minuit(atest.chisq,startpar,name=names,grad=atest.calcgrad)
#gMinuit = Minuit(chisq,startpar,name=names)
gMinuit.print_level = 1 # 3 has lots more details
gMinuit.strategy = 1

# set limits...
for aname in names:
    gMinuit.limits[aname] = (-10,10.)
    gMinuit.errors[aname] = 0.01

# fix a parameter
gMinuit.fixed['a'] = True

# print setup
gMinuit.init_params

# do fit
gMinuit.migrad()

# print out results
print(gMinuit.values)
print(gMinuit.fmin)
print(gMinuit.errors)
print(gMinuit.covariance)

# release a
gMinuit.fixed['a'] = False

# do fit
gMinuit.migrad()

# print out results
print(gMinuit)
print(gMinuit.values)
print(gMinuit.fmin)
print(gMinuit.errors)
print(gMinuit.covariance)

# pickle
pickle.dump(gMinuit,open('test.pkl','wb'))

pMinuit = pickle.load(open('test.pkl','rb'))

print(pMinuit.values)
print(pMinuit)

Thanks for reporting, I am investigating.