Closed bhclowers closed 6 years ago
Thanks for reporting it, I submitted a patch. I actually think this embarrassing bug was already there for longer, because the tests made for this example explicitly gave a name to the dependent variable, and therefore this bug was never triggered. The tests have been modified to make sure this doesn't happen again.
So after cloning the most recent update and running:
python3 setup.py install --user
I get the following result which still seems a bit odd. Did I do something wrong here?
from symfit import parameters, Fit, Equality, GreaterThan
x, y = parameters('x, y')
model = 2 * x * y + 2 * x - x**2 - 2 * y**2
constraints = [
Equality(x**3, y),
GreaterThan(y, 1),
]
fit = Fit(model, constraints=constraints)
fit_result = fit.execute()
****Output 1:
/home/user/.local/lib/python3.5/site-packages/symfit/core/fit.py:1654: RuntimeWarning: invalid value encountered in double_scalars
return 1 - SS_res/SS_tot
****Output 2:
>>fit_result.params
OrderedDict([('x', nan), ('y', nan)])
Actually the readme has not been updated properly it appears, try negating the model since Fit
always minimizes and here we need to maximize:
fit = Fit(- model, constraints=constraints)
This was forgotten when changing the API in 0.4.x, so thanks again for pointing it out!
After banging my head against this for a while, I still appear stuck. I can get the simple example to complete but when I try to extend the concept I am getting some odd behavior. In short, I have the following code and after executing the fit the error thrown is saying that that parameter (theta1) is not present. Is this a syntax/keyword argument issue? If so can you please nudge me in the right direction?
import numpy as np
from symfit import parameters, Fit, GreaterThan
phi1, phi2, theta1, theta2 = parameters('phi1, phi2, theta1, theta2')
x, y = variables('x, y')
model_dict = {y: (1+x*theta1+theta2*x**2)/(1+phi1*x*theta1+phi2*theta2*x**2)}
constraints = [GreaterThan(theta1, theta2)]
xdata = np.array([0., 0.000376, 0.000752, 0.0015 , 0.00301 , 0.00601 , 0.00902 ])
ydata=np.array([1., 1.07968041, 1.08990638, 1.12151629, 1.13068452,1.15484109, 1.19883952])
phi1.value = 0.845251484373516
phi1.fixed = True
phi2.value = 0.7105427053026403
phi2.fixed = True
fit = Fit(model_dict, x=xdata, y=ydata, constraints=constraints)# Feed in the observed x and y data
fit_result = fit.execute()
***Error thrown:
TypeError: missing a required argument: 'theta1'
Damn, you are good at finding bugs. This one seems to be caused by fixing the values of the phi
's, if I remove that the fit runs.
So after some searching it seems that the bug is caused by some of the changes made in PR #151, so I'm also going to mention @pckroon to also get his eyes on this. And I see that this PR was made in order to fix issue #150 which you also made, so thank you for your patience ;).
The problem lies in this: the Minimizer.initial_guesses
property returns the initial guesses for the non-fixed parameters. The objective has been partial
ed to expect only those arguments, the fixed ones have been provided by partial:
self.objective = partial(objective, **{p.name: p.value for p in self._fixed_params})
However, the constraints have never been adapted to this, so they are still len(self._fixed_params)
short. Therefore, the solution is to also partial
the constraints. However, scipy_constraints
is a staticmethod
so it is agnostic about which parameters are fixed. Some thought is needed.
Why is it that every time someone uses my code they find bugs? :')
I think the architectural issue is fairly simple to solve here. ConstrainedMinimizer
wraps the symfit style constraints to get rid of the fixed parameters, and the Scipy wrapper remains unchanged (similar to what we do with the jacobian). I'm fairly swamped with work at the moment though, so I'll leave the implementation to @tBuLi.
In principle that's a nice idea. But it turns out not to be quite that simple, because of the MRO. I will watch Super Considered Super again, and then try again :P.
(BaseMinimizer is needed to know which parameters are fixed, and then we could do a simple partial after. But ScipyMinimize's init is called before BaseMinimizer, so the most obvious solution doesn't work.)
@tBuLi Wish I could help on the other issue, however, if you were able to get it to run without the phi parameters being fixed, could you please send me the code you ran and output values? I am having trouble making that happen on my end. Even with those values not being fixed, I might be able to make this work for our particular purposes. However, it would be great to be able to used constrained parameters along with fixed ones.
I'm not sure this is related but in the latest version that I cloned even the basic examples seem to be throwing an error associated with an AttributeError:
from symfit import parameters, variables, Fit, Model
xdata = [1.0, 2.0, 3.0, 4.0, 5.0]
ydata = [2.3, 3.3, 4.1, 5.5, 6.7]
yerr = [0.1, 0.1, 0.1, 0.1, 0.1]
a, b = parameters('a, b')
x, y = variables('x, y')
model = Model({y: a * x + b})
fit = Fit(model, x=xdata, y=ydata, sigma_y=yerr)
fit_result = fit.execute()
Error:
/anaconda2/envs/py36/lib/python3.6/site-packages/sympy/printing/codeprinter.py in _print_Variable(self, expr)
342
343 def _print_Variable(self, expr):
--> 344 return self._print(expr.symbol)
345
346 def _print_Statement(self, expr):
AttributeError: 'Variable' object has no attribute 'symbol'
To your first comment: I literally ran your example except that I removed the lines saying they had to be fixed:
import numpy as np
from symfit import parameters, Fit, GreaterThan, variables
phi1, phi2, theta1, theta2 = parameters('phi1, phi2, theta1, theta2')
x, y = variables('x, y')
model_dict = {y: (1+x*theta1+theta2*x**2)/(1+phi1*x*theta1+phi2*theta2*x**2)}
constraints = [GreaterThan(theta1, theta2)]
xdata = np.array([0., 0.000376, 0.000752, 0.0015 , 0.00301 , 0.00601 , 0.00902 ])
ydata=np.array([1., 1.07968041, 1.08990638, 1.12151629, 1.13068452,1.15484109, 1.19883952])
phi1.value = 0.845251484373516
phi2.value = 0.7105427053026403
fit = Fit(model_dict, x=xdata, y=ydata, constraints=constraints)# Feed in the observed x and y data
fit_result = fit.execute()
print(fit_result)
Parameter Value Standard Deviation
phi1 8.549886e-01 1.977125e-01
phi2 1.600773e+02 3.472350e+07
theta1 2.074183e+03 4.091964e+03
theta2 -1.557679e+01 3.396675e+06
Fitting status message: Optimization terminated successfully.
Number of iterations: 117
Regression Coefficient: 0.950091684637884
I leave it up to you to plot it to see if it makes sense, but judging from the Regression Coefficient it should be pretty good.
To your second comment: that code example is not complete enough because it doesn't contain a print statement, whereas the traceback indicates that it's a printing issue. So I think the code snippet you posted is not exactly what you actually ran? And like you already said, it's probably not a related issue, so please start a separate issue for that.
Let me know if fitting without fixing works on your end too!
P.s., as a quick and dirty workaround in the meantime you could also set very tight bounds on the phi
's, so that they are practically fixed.
@tBuLi with the reversion of sympy I was able to fix the values of phi1 and phi2 in the above example and get the constraints to work out. Cheers.
Fixed with PR #168. Thank you for reporting this problem.
As of version 0.4.2 the example provided on the front of the github page for constraints appears to throw and error (at least on my system Python 3.5.2). Any ideas would be appreciated.
Error output: