jpivarski / pyminuit

Automatically exported from code.google.com/p/pyminuit
GNU General Public License v2.0
14 stars 3 forks source link

migrad() ignores limits??? #1

Open GoogleCodeExporter opened 9 years ago

GoogleCodeExporter commented 9 years ago
Hi, it seems that migrad() ignores a pre-defined limit -- or I do not know
how to set it properly.

Example:

fitter = minuit.Minuit(chi2)
fitter.limits['k'] = (0.0001,5.)   # so 'k' should be inside [0.0001,5]?
fitter.migrad()

print fitter.values
{'k': -0.063252887650227116, 'zp': 22.130823824765077, 'gamma':
1.2702726579451527}

What am I doing wrong???

I am using pyminuit-1.0.1.tgz on a Debian Etch system (Python 2.4.4)

Any suggestion is very much apprechiated!
Marcus

Original issue reported on code.google.com by marcus.h...@gmail.com on 22 Feb 2008 at 12:38

GoogleCodeExporter commented 9 years ago
pyminuit passes limits directly to Minuit, so this is a question about Minuit's
behavior.  I know that setting fitter.limits['k'] = (0.0001, 5.) doesn't
automatically place the initial value of 'k' between 0.0001 and 5.  It's still 
at its
default initial value of 0.  However, I'm surprised that Minuit doesn't fail 
(and
therefore pyminuit throw an exception) when you attempt to minimize something 
where
the parameter starts outside of its allowed range.  If that's true, then I'll 
add a
check in pyminuit that throws the exception (perhaps a ValueError).

Let me know if that's how it works.  You can check the value of 'k' through
fitter.values['k'] before or after fitting.

Original comment by jpivar...@gmail.com on 22 Feb 2008 at 12:51

GoogleCodeExporter commented 9 years ago
It is like you described it. Minuit leaves the allowed range for k, even if I 
set an
initial value.  Example (inside ipython shell):

In [152]: fitter = minuit.Minuit(chi2, limit_k=(0.0001,5.) )

In [153]: fitter.limits['k']
Out[153]: (0.0001, 5.0)

In [154]: fitter.values['k']
Out[154]: 0.0

In [155]: fitter.migrad()

In [156]: fitter.values['k']
Out[156]: -0.063252887650227116

In [157]: fitter = minuit.Minuit(chi2, limit_k=(0.0001,5.) )

In [158]: fitter.values['k']
Out[158]: 0.0

In [159]: fitter.values['k'] = 0.02

In [160]: fitter.limits['k']
Out[160]: (0.0001, 5.0)

In [161]: fitter.values['k']
Out[161]: 0.02

In [162]: fitter.migrad()

In [163]: fitter.values['k']
Out[163]: -0.063252789538007254

Original comment by marcus.h...@gmail.com on 22 Feb 2008 at 1:02

GoogleCodeExporter commented 9 years ago
Yikes!  In the second example, Minuit does appear to be behaving badly.  I 
remember
testing this, years ago, possibly with a non-final version of Minuit.  Well, the
Minuit which is included in this package is no longer maintained, so I can't 
ask them
to fix that.  A solution for your needs is to switch to pyminuit2 (also on 
Google
code), which uses the actively-maintained Minuit2 package, though you need to 
install
Minuit2 somehow and get the compilation to work.

I'm going to look at this when I have a chance.  I may be able to find the bug 
in
Minuit and fix it.  (Because it was something that worked before, it's probably 
a
trivial mistake.)  Then pyminuit will ship with a non-standard version of 
Minuit, but
I think that's acceptable.

Another solution for your needs is to implement the limits in your chi^2 
function. 
Internally, Minuit passes the limited parameter through a function based on
arctangents or something, to effectively change the metric close to the 
boundaries. 
It then has to convert the error bounds back through that function, which is a 
small
effect if you're in the linear regieme of the arctangent, if the local minimum 
is not
close to the physical boundary.

Original comment by jpivar...@gmail.com on 22 Feb 2008 at 2:51

GoogleCodeExporter commented 9 years ago
Wait a minuit!  Wait a minuit!  Could you please post your chi2 function?  When 
I
tried a generic test-function, I saw the correct behavior.

-- Jim

>>> m = minuit.Minuit(lambda x, y: ((x-1)**2 + (y-1)**2), limit_x=(-0.1,0.1),
limit_y=(-0.1, 0.1))
>>> m.limits
{'y': (-0.10000000000000001, 0.10000000000000001), 'x': (-0.10000000000000001,
0.10000000000000001)}
>>> m.migrad()
>>> m.values
{'y': 0.09999999684054435, 'x': 0.09999999684054435}

Original comment by jpivar...@gmail.com on 3 Mar 2008 at 9:14

GoogleCodeExporter commented 9 years ago
Hi there!
first of all Jim thanks for your work and that you made it available! I like it 
a lot.
I have fixed that bug in the intermediate file:

     self->upar->removeLimits(i);
     self->upar->setLimits(i, PyFloat_AsDouble(PyTuple_GetItem(limit, 0)),
PyFloat_AsDouble(PyTuple_GetItem(limit, 1)) );
         //original lines:
     //self->upar->setLowerLimit(i, PyFloat_AsDouble(PyTuple_GetItem(limit, 0)));
     //self->upar->setUpperLimit(i, PyFloat_AsDouble(PyTuple_GetItem(limit, 1)));

seems by calling "setUpperLimit", the lower limit is deleted again. 
Cheers
Johannes.

Original comment by jo.greg...@googlemail.com on 19 Sep 2008 at 5:12

GoogleCodeExporter commented 9 years ago
Well, when I tested it before, I got the correct behavior, but I've been 
getting more
comments about limits not working, so it must be something that depends on the 
FCN
somehow.  Thanks, Jo, for the bug-fix! I've made a new version: 1.1.1.  (Still 
works
for me, so I have no objection.)

-- Jim

Original comment by jpivar...@gmail.com on 21 Sep 2008 at 12:17

GoogleCodeExporter commented 9 years ago
I seem to be getting this problem in pyminuit v1.2.1 (on Ubuntu 12.04 LTS, 
64-bit, python v2.7).

I am only fitting a single weighting parameter, which I limit to (0.0, 1.0), 
and pyminuit converges fine on the upper bound, but then it jumps to NEGATIVE 
values to find the lower bound.

Is this perhaps a regression?

Original comment by morse...@gmail.com on 6 Jun 2014 at 4:21