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

Separability of parts of bifs #22

Open
RossBoylan opened this issue Dec 5, 2019 · 4 comments
Open

Separability of parts of bifs #22

RossBoylan opened this issue Dec 5, 2019 · 4 comments
Labels
design concerning the intended behavior of the application

Comments

@RossBoylan
Copy link
Member

This is closely related to #15.

Narrow question

@kyoung21b many bump-related items are created only after discovering basis="fourier". Should bumps actually be tied to the basis? The bump info is not saved with the basis object. But it's written as if other bases might use other bump types, or perhaps be unable to use bumps at all.

Broader issue

Also mostlly @kyoung21b. To what extent can we separate concerns into separate spheres? For example, it appears that some of the logic and parameters depend on the likelihood x prior distribution type. There are parameters defined on bifs that seem only to be relevant for some of those, e.g., Rician.

Example 1

The idea is that instead of

        myShape = init_image.shape
        if self.imdim == 1:
            self.kdist = self.bas.kdist1D(*myShape)
            self.k_image = self.bas.tx1(self.init_image) # Get k-space image
        elif self.imdim == 2:
            self.kdist = self.bas.kdist2D(*myShape)
            self.k_image = self.bas.tx2(self.init_image) # Get k-space image
        elif self.imdim == 3:
            self.kdist = self.bas.kdist3D(*myShape)
            self.k_image = self.bas.txn(self.init_image) # Get k-space image

(I've used Python's '*' operator to simplify the existing code) you'd have something like

    self.k_image = self.basis.k_image(self)

where self.basis is some kind of basis object, self is an argument so basis.k_image() can get needed info from the bifs object, and k_image() returns an appropriate k-space image while setting kdist in self.basis.

There is an argument in favor of passing the needed components explicitly to basis.k_image() rather than having it extract them from the bifs object. The advantage of the formulation I gave is that it works better if different classes of basis objects need different info. That's all somewhat theoretical since our mainline only has one possible basis.

Example 2

            if self.prior == "Gaussian" and self.likelihood == "Gaussian":
                self.bifsk_image = self.bifs_map_gauss_gauss(self.prior_mean,self.prior_std2,self.mod_image,self.ksd2)
            elif self.prior == "Gaussian" and self.likelihood == "Rician":
                conj = self.bifs_map_gauss_gauss(self.prior_mean,self.prior_std2,self.mod_image,self.ksd2)
                besind = np.zeros(self.init_image.shape,dtype=int)
                besind[np.where(conj > self.bessel_approx_lims[1])] = 1
                besind[np.where(conj > self.bessel_approx_lims[2])] = 2
                besind[np.where(conj > self.bessel_approx_lims[3])] = 3
                self.bsa = self.bessel_approx_array[besind,:]
                self.bifsk_image = self.bifs_map_gauss_rice(self.prior_mean,self.prior_std,self.mod_image,self.likelihood_scale)
            else:

becomes

   self.bifsk_image = self.likelihood.bifs_map(self)

where self.likelihood is an object, not a string, with a class that depended on the type of prior and likelihood. The rician version would have all the bessel function machinery and Rician-specific parameters tucked away inside of it.

@kyoung21b
Copy link
Collaborator

kyoung21b commented Dec 5, 2019 via email

@RossBoylan
Copy link
Member Author

Thanks for the feedback. So the answer to my narrow question is "Yes, bumps are tied to the basis."

I got into this mostly because of trying to reason about what things need to be updated if various parameters change for #15. If certain parameters only go with certain other choices, e.g., if basis is fourier then there are bumps, if distribution is Rician there are other auxiliary parameters, my inclination would be to keep them out of the main bifs class.

This also affects the documentation, as there are many variables of bifs (the class) that are discussed as if they apply generally, when they don't.

The main complication I can foresee, which is probably present regardless of bifs internals, is that if some parameters are only present some of the time, how does the GUI handle that? I think at the moment it just always allows you to set any parameter, even if the parameter being set will have no effect, like a Rician parameter when you have a Gaussian likelihood.

@kyoung21b it might be good to discuss face to face or eface to eface (like a phone call 😃 ), or maybe in this thread, why you found the wavelet basis didn't fit into the current master branch.

Slightly tangential background: lazy evaluation

In general, the strategy I'm hoping to pursue is lazy evaluation: nothing gets computed until BIFS_MAP. Then if parameters are changed--which would only be via a function call--everything that depends on it is wiped out, only to be computed at the next BIFS_MAP. @kyoung21b Are any of the preliminary calculations expensive?

Simple example of lazy strategy

class X has 3 main variables, a, b, c (like fourier transform of original image, prior distribution, and final image in original space). b depends on a and auxiliary parameters; c depends on a and b and some auxiliary parameters. Then, for example, if an auxiliary parameter for b changes then b and c are set to None. When do_stuff() is called it requests value c via getc(), which requests b via getb() and so on. getb discovers that b is None and recomputes it (otherwise, it just returns the already computed value).

@kyoung21b
Copy link
Collaborator

kyoung21b commented Dec 5, 2019 via email

@RossBoylan
Copy link
Member Author

RossBoylan commented Jan 25, 2022

Summarizing some other relevant comments from others, possibly inaccurately 😃

Karl: wavelets proved different enough from a fourier basis that they have moved into a separate product.

John K: Many choices are a function of the combination of the prior and the likelihood; some combinations may not be present, either because they are nonsense or because we can't handle them.

@RossBoylan RossBoylan added the design concerning the intended behavior of the application label Jan 26, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
design concerning the intended behavior of the application
Projects
None yet
Development

No branches or pull requests

2 participants