Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #840 #841

Merged
merged 1 commit into from
Feb 19, 2023
Merged

Fix #840 #841

merged 1 commit into from
Feb 19, 2023

Conversation

JeppeKlitgaard
Copy link
Contributor

@JeppeKlitgaard JeppeKlitgaard commented Feb 10, 2023

Description

Fixes: #840

Type of Changes
  • Bug fix

Skipped most steps out of laziness since this is a tiny fix

@newville
Copy link
Member

@JeppeKlitgaard What if x does not have a shape attribute?

@JeppeKlitgaard
Copy link
Contributor Author

JeppeKlitgaard commented Feb 10, 2023

@newville I believe I came around this by using np.shape rather than relying on the attribute (note: np.shape(x), not x.shape). This relaxes the requirement to x being a Numpy arraylike, which I believe it should be anyway for use in lmfit

@newville
Copy link
Member

@JeppeKlitgaard I think it could be ok to expect that x is array-like here. While we actually do not demand that in general or for user-defined model functions, most (perhaps all) of the other built-in models do use numpy/scipy ufuncs that will also expect x to be array-like.

I think you are right that using np.shape(x) vs x.shape is a good idea, permitting more types and defaulting to a length-1 array for many cases. I might suggest having

try:
    c = c * np.ones(np.shape(x))
except TypeError:
    pass
return c

@newville
Copy link
Member

@JeppeKlitgaard It would also be good to apply the same approach to the ComplexConstantModel.

@JeppeKlitgaard
Copy link
Contributor Author

JeppeKlitgaard commented Feb 19, 2023

@newville

Sorry for not getting back to you!

My personal preference would definitely be to only have a single return type that is always reliably arraylike with the same shape as the independent variable – I am fairly sure there are bits of lmfit that rely on this behaviour as well. For example, the following raises a TypeError when the output of a model is not an array of shape matching the independent variable array:

x = [1,2,3]
y = [1,2,3]

model = ConstantModel()
params = model.make_params()
fit = model.fit(y, params, x=x)

fit.plot()
# Raises `TypeError` without this fix

This suggests to me that:

return c * np.ones(np.shape(x))

is preferable over:

try:
    c = c * np.ones(np.shape(x))
except TypeError:
    pass
return c

@JeppeKlitgaard
Copy link
Contributor Author

@newville
I have updated the PR to also include the same fix for ComplexConstantModel as you suggested.

@newville
Copy link
Member

@JeppeKlitgaard OK, I will merge this and then fix it myself.
We cannot promise that plot will work for all cases, but it would work with your example and the try/except block.

But in case np.ones(np.shape(x)) fails with a TypeError, it would help to return something sensible instead of failing.
And, yeah, almost everyone will pass in something nd-array-like, and all of the builtin models will expect that numpy/scipy ufuncs will work on x, but we actually do not require that independent variables be nd-array-like.

@newville newville merged commit c1c515c into lmfit:master Feb 19, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

ConstantModel returns wrong shape
2 participants