-
Notifications
You must be signed in to change notification settings - Fork 0
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
Support lsqfit.Multifitter objects #10
Comments
Thanks, @millernb, for the suggestions and proposed solutions. That is indeed a relevant but also complicated feature which would be useful to have. I feel that this requires changing significant part of the API, but it's also at an early enough point to start doing so. We should, at some point chat about the details and also chat with @walkloud about when things for the core fitter should be usable. May I ask: what is the difference between using MultiFitterModel and returning multiple data values. def fcn(x, p):
...
return {"key1": ..., "key2": ...} Is it just "a cleaner API" or is there a more fundamental difference. Before I going into some thoughts I have, I'd like to mention two guiding principles I'd like to follow:
Details thoughtthis is also to remind myself at a later point This actually brings me to a more fundamental discussion I had with @walkloud (and someone else a year ago). In principle the There is also some discrepancy when trying to conceptually discriminate dependent variable and meta arguments like, the number of exponents as an input for the fit function which I kind of hacked into the fits using the new In other words, I really like the idea of tagging data, initializing fit functions, and just using This obviously means that we have to modify the way the fit GUI is set up and configured (which you address in your proposal). I would certainly like to avoid to have too many if clauses and different APIs depending on specific scenarios. I.e., differences between fit1 = nonlinear_fit(...)
fit2 = MultiFitterModel(...).lsqfit(...) So I might actually favor, after some additional thoughts, following the This may simplify the Regarding the customizations of plots: In the long run, I envision some custom "grab all the elements available in the content and drag and drop windows as you like them in the GUI." This certainly only works for distinguished figures so one needs some way to let the API know how to look them up. Your suggestions here looks reasonable. |
Okay, I was able to recreate the Linear example without using import lsqfit
import gvar as gv
import numpy as np
x = np.array([1,2,3,4])
y = dict(
d1=['1.154(10)', '2.107(16)', '3.042(22)', '3.978(29)'],
d2=['0.692(10)', '1.196(16)', '1.657(22)', '2.189(29)'],
d3=['0.107(10)', '0.030(16)', '-0.027(22)', '-0.149(29)'],
d4=['0.002(10)', '-0.197(16)', '-0.382(22)', '-0.627(29)'],
)
prior = gv.gvar(dict(a='0(1)', s1='0(1)', s2='0(1)', s3='0(1)', s4='0(1)'))
def fitfcn(x, p):
output = {}
for key in ['d1', 'd2', 'd3', 'd4']:
slope = p['s%s'%(key[1:])]
output[key] = p['a'] + slope *x
return output
fit = lsqfit.nonlinear_fit(data=(x, y), fcn=fitfcn, prior=prior)
print(fit) This output is identical to that of the MultiFitter example above. |
Here's a more practical extension of the Linear example where the x data differ. import lsqfit
import gvar as gv
import numpy as np
x = dict(
d1=np.array([1, 2, 3, 4]),
d2=np.array([1, 2, 3, 4]),
d3=np.array([1, 2, 3, 4]),
d4=np.array([1, 2, 3, 4]),
d5=np.array([5, 6, 7, 8])
)
y = dict(
d1=['1.154(10)', '2.107(16)', '3.042(22)', '3.978(29)'],
d2=['0.692(10)', '1.196(16)', '1.657(22)', '2.189(29)'],
d3=['0.107(10)', '0.030(16)', '-0.027(22)', '-0.149(29)'],
d4=['0.002(10)', '-0.197(16)', '-0.382(22)', '-0.627(29)'],
d5=['1.869(10)', '2.198(16)', '2.502(22)', '2.791(29)']
)
prior = gv.gvar(dict(a='0(1)', s1='0(1)', s2='0(1)', s3='0(1)', s4='0(1)'), s5='0(1)')
def fitfcn(x, p):
output = {}
for k in x:
slope = p['s%s'%(k[1:])]
output[k] = p['a'] + slope *x[k]
return output
fit = lsqfit.nonlinear_fit(data=(x, y), fcn=fitfcn, prior=prior)
print(fit) |
Interestingly, this actually will run if you wrap a |
Just copied your script. Indeed the regular plots look weird, but the residuals look fine. I'll check what's going wrong. |
…ectly This addresses one comment in #10
Ok, this should be fixed now. |
Is this infrastructure sufficient for now to be used for the fits you are doing (with some wrapping around)? If so, I would probably like to shift the conversation about chained fits and |
Yes, I think this is fine -- I'm convinced that A couple closing thoughts: (1) Regarding chained fits, it's probably relevant to point out that the fitter = lsqfit.MultiFitter(models=models)
fit = fitter.chained_lsqfit(data=data, prior=prior) But of course this can obviously be implemented without appealing to (2) I think, if we someday do want to support |
Thanks, @millernb. I agree with your second point and like to keep this issue open as a reminder (if more time or resources in form of volunteers are available :)) |
With #32, I have now added a feature that the The key idea is that the If we intend to extend this capability, this would be the right place. |
Background
See here for documentation on the Multifitter class, though more insight can be gleaned from the git source on
lsqfit._extras.unchained_nonlinear_fit
.Multifitter support is desirable for correlator as well as chiral fits. (However, it's worth noting that we technically could avoid using Multifitter by manually chaining fits.)
Proposed example
As a test case, we should try to support the example from the
lsqfit
documentation.Difficulties
Difficulty 1:
fit.fcn
Unfortunately, Multifitter fits lack many of the attributes we currently assume a
fit
has. To delve into this a bit more, consider theget_fit_bands
method,and more specifically, consider
fit.fcn
. A Multifitter fit also contains afit.fcn
, but it is called slightly differently (fit.fcn(fit.p)
-- nox
) and has a slightly different return (a dict instead of an array) . For example. from the Linear model example above,fit.fcn(fit.p)
returnsThis is probably the simplest problem to correct, as it only requires a switch depending on whether the fit is derived from the Multifitter class or not; but digging a little deeper, we see that this leads to a more onerous difficulty.
Difficulty 2:
fit.x
The more pressing problem is
fit.x
, which is currently used to construct the domain of our fit plots. A Multifitter fit does not have a standardizedfit.x
(technically it does have afit.x
, but it is initialized toFalse
). Rather, the analogousx
depends on your model. A couple examples:In the Linear example above,
fit.x
would most similar tox
inside aLinear
object. We actually can get the values of x from the fit object, but the call is rather obtuse:fit.fitter_args_kargs[1]['models'][k].x
for model k. Moreover, each linear model needn't share the same valuesx
(although they do in this example), so we would need to get the max/min values ofx
for each model, then get the max/min values of x from that list.Correlator models are basically the same as Linear models as far as
x
analogues are concerned. However, there are a couple ambiguities here: (1) we don't need to call itx
(in myBaryonCorrelatorModel
, for example, I call itt
). (2) As an example of a more troublesome edge case, note that since we fit a range oft
, one could alternatively formulate aBaryonCorrelatorModel
as having at_start
andt_end
rather than an array of times; that is, ourx
variable needn't even directly describe an array.By far the most challenging type of fit to implement will be chiral fits. Unlike the previous two examples, chiral fits have multiple independent variables (lattice spacing, light quark mass, etc) and non-standardized names (
a
,eps_a
,eps2_a
, etc). Further, these aren't proper independent variables (in the typical least-squares fit use case) since they have uncertainty. Of course, in practice we account for this fact by moving the "x-data" into the prior also, but this means we will have to specify which parts of the priors should be varied when constructing the plots; thus chiral fits require tracking correlated priors inlsqfit-gui
.Difficulty 3: observables with different scales/dimensions
Fitted observables might or might not be comparable on the same plot. For example, effective masses usually can be compared, but wave function overlaps often cannot; it may occasionally make sense to compare
M_proton
andM_Delta
on a plot, but it would never make sense to plotM_proton
andF_K/F_pi
together.Therefore must be able to specify which observables should be included in the same plot.
Proposal
I propose that
meta_config
should contain information about the x-variable(s) and plot(s). Let me list a few hang-ups that should be addressed eventually but which I'll ignore for now:As an example for how we might implement the
x
and plotting limitations for a Multifitter model, let's consider the Linear model above and a baryon correlator model.1. Linear model
For the linear model, the only thing that's from our
fit
object is the x-variable for our plots. We might writeWe could imagine repeating this adding a fifth line to our simultaneous fits except with data out near
x=1000
. In this case, we probably would want to plot lines 1-4 together but line 5 separately. We might writeHere
dN
corresponds to the datatag for eachMultifitterModel
.As an additional suggestion, it might be convenient to be able to manually group/ungroup observables in the web UI.
2. Correlator model
For reference, consider the example
BaryonCorrelatorModel
below.Assume I have two models named
PS
andSS
corresponding to the two differently smeared sets of correlator data. Plottingfitfcn
is unlikely to offer insight into the goodness-of-fit. Instead we'd like to consider the effective mass/wf plots.Since
fnc_effective_mass
andfcn_effective_wf
are defined inBaryonCorrelatorModel
, we can access these functions throughfit
withfit.fitter_args_kargs[1]['models'][0].fnc_effective_mass
etc. We'd like to plot the effective masses together but not the effective wf overlaps.In this case, we might write
The text was updated successfully, but these errors were encountered: