Repository: lmfit/lmfit-py

Issue:
parameter.set doesn't set value as expected
#### Description
Changing/updating the value for a fit parameter at the same time as min and max values, seems to enforce the old min/max values instead of the new ones for the value. The example hopefully makes this clearer ;)

###### A Minimal, Complete, and Verifiable example
import lmfit

p = lmfit.Parameters()
p.add('test', value=5, min=4, max=10)
print(p)
p['test'].set(value=22, min=20, max=30)
print(p)

results in

Parameters([('test', <Parameter 'test', value=5, bounds=[4:10]>)])
Parameters([('test', <Parameter 'test', value=10, bounds=[20:30]>)])

Whereas I would have expected a value of 22 in the second print statement.
A workaround seems to be to set min and max first to -inf/inf, but I was wondering, if this is intended behavior or a bug.

###### Version information

Python: 3.7.6 (default, Jan  8 2020, 13:42:34) 
[Clang 4.0.1 (tags/RELEASE_401/final)]

lmfit: 1.0.0, scipy: 1.4.1, numpy: 1.18.1, asteval: 0.9.18, uncertainties: 3.0.3


Thanks for providing lmfit! Very useful and very nice user interface for fitting.
parameter.set doesn't set value as expected
#### Description
Changing/updating the value for a fit parameter at the same time as min and max values, seems to enforce the old min/max values instead of the new ones for the value. The example hopefully makes this clearer ;)

###### A Minimal, Complete, and Verifiable example
import lmfit

p = lmfit.Parameters()
p.add('test', value=5, min=4, max=10)
print(p)
p['test'].set(value=22, min=20, max=30)
print(p)

results in

Parameters([('test', <Parameter 'test', value=5, bounds=[4:10]>)])
Parameters([('test', <Parameter 'test', value=10, bounds=[20:30]>)])

Whereas I would have expected a value of 22 in the second print statement.
A workaround seems to be to set min and max first to -inf/inf, but I was wondering, if this is intended behavior or a bug.

###### Version information

Python: 3.7.6 (default, Jan  8 2020, 13:42:34) 
[Clang 4.0.1 (tags/RELEASE_401/final)]

lmfit: 1.0.0, scipy: 1.4.1, numpy: 1.18.1, asteval: 0.9.18, uncertainties: 3.0.3


Thanks for providing lmfit! Very useful and very nice user interface for fitting.


Discussion:
@arunpersaud yes, that should be fixed.   Are you up for making a Pull Request?
I'll give it a try, but I'm not sure if I understand lmfit internals enough at the moment... guess this might be a good opportunity to look into it a bit more. I'll let you know here in case I'm not able to fix it (will know in 1-2 days).
@arunpersaud yes, that should be fixed.   Are you up for making a Pull Request?
I'll give it a try, but I'm not sure if I understand lmfit internals enough at the moment... guess this might be a good opportunity to look into it a bit more. I'll let you know here in case I'm not able to fix it (will know in 1-2 days).

Resolving patch:
diff --git a/lmfit/parameter.py b/lmfit/parameter.py
--- a/lmfit/parameter.py
+++ b/lmfit/parameter.py
@@ -631,10 +631,6 @@ def set(self, value=None, vary=None, min=None, max=None, expr=None,
             par.set(brute_step=0)     # removes brute_step
 
         """
-        if value is not None:
-            self.value = value
-            self.__set_expression('')
-
         if vary is not None:
             self.vary = vary
             if vary:
@@ -646,6 +642,12 @@ def set(self, value=None, vary=None, min=None, max=None, expr=None,
         if max is not None:
             self.max = max
 
+        # need to set this after min and max, so that it will use new
+        # bounds in the setter for value
+        if value is not None:
+            self.value = value
+            self.__set_expression("")
+
         if expr is not None:
             self.__set_expression(expr)
 


Test patch:
diff --git a/tests/test_parameter.py b/tests/test_parameter.py
--- a/tests/test_parameter.py
+++ b/tests/test_parameter.py
@@ -125,6 +125,11 @@ def test_parameter_set_value(parameter):
     changed_attribute_values = ('a', 5.0, True, -100.0, 100.0, None, 5.0, 1)
     assert_parameter_attributes(par, changed_attribute_values)
 
+    # check if set value works with new bounds, see issue#636
+    par.set(value=500.0, min=400, max=600)
+    changed_attribute_values2 = ('a', 500.0, True, 400.0, 600.0, None, 5.0, 1)
+    assert_parameter_attributes(par, changed_attribute_values2)
+
 
 def test_parameter_set_vary(parameter):
     """Test the Parameter.set() function with vary."""